TLE on #4 树上二分做法,有注释
查看原帖
TLE on #4 树上二分做法,有注释
1351126
General0826楼主2024/10/14 11:47
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll N=2e5+5;
ll n,m,a[N],l,r,op;
namespace LineTree{
	const ll M=N<<2;
	#define lt (cur<<1)
	#define rt ((cur<<1)|1)
	#define mid (L+R>>1)
	long long num[M];
	ll mins[N],lz[M];
	bool unb(ll l,ll r,ll L,ll R){ // un banana 不相交(香蕉)	 
		return l>R||L>r;
	}
	void sq(ll cur,ll len,ll w){ //处理 
		num[cur]=len*w; 
		mins[cur]=w;
		lz[cur]=w;
	}
	void up(ll cur){ //上传 
		num[cur]=num[lt]+num[rt];
		mins[cur]=min(mins[lt],mins[rt]);
	}
	void down(ll cur,ll L,ll R){ //下放 
		if(lz[cur]!=-1)	sq(lt,mid-L+1,lz[cur]); 
		if(lz[cur]!=-1) sq(rt,R-mid,lz[cur]);
		lz[cur]=-1;
	}
	ll sumq(ll cur,ll l,ll r,ll L,ll R){ //求和 
		if(l<=L&&R<=r){
			return num[cur];
		}else if(!unb(l,r,L,R)){
			ll sum=0;
			down(cur,L,R);
			sum+=sumq(lt,l,r,L,mid);
			sum+=sumq(rt,l,r,mid+1,R);
			up(cur);
			return sum;
		}
		return 0;
	}
	void covmi(ll cur,ll l,ll r,ll L,ll R,ll w){  //覆盖操作 
		if(l<=L&&R<=r){
			sq(cur,R-L+1,w);
		}
		else if(!unb(l,r,L,R)){
			down(cur,L,R);
			covmi(lt,l,r,L,mid,w);
			covmi(rt,l,r,mid+1,R,w);
			up(cur);
		}
	}
	void build(ll cur,ll L,ll R){ 
		lz[cur]=-1;
		if(L==R){
			mins[cur]=num[cur]=a[L];
			return ;
		}
		build(lt,L,mid);
		build(rt,mid+1,R);
		up(cur);
	}
	ll minq(ll cur,ll L,ll R,ll w){ //找到第一个小于w的
	//	cout<<L<<' '<<R<<' '<<mins[cur]<<'\n';
		if(L==R){
			return L;
		}
		down(cur,L,R);
		ll op;
		if(mins[lt]<=w)
			op=minq(lt,L,mid,w);
		else
			op=minq(rt,mid+1,R,w);
		up(cur);
		return op;
	}
	ll efsum(ll cur,ll L,ll R,ll w){ //找到前缀和第一个大于w的 
	
		if(L==R){
			if(w<num[cur]){
				return L;
			}	
			else 
				return L+1; 
		} 
		ll op;
		down(cur,L,R); 
		if(w<=num[lt]) 
			op=efsum(lt,L,mid,w); 
		else 
			op=efsum(rt,mid+1,R,w-num[lt]);
		up(cur);
		return op; 
	}
}
using namespace LineTree;
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	cin>>n>>m;
	for(ll i=1;i<=n;i++)
		cin>>a[i];
	build(1,1,n);
	for(ll i=1;i<=m;i++){
		cin>>op>>l>>r;
		if(op==1){
			if(mins[1]<=r){ //有比r小的 
				ll u=minq(1,1,n,r); 
				if(u<=l) // 且在l的左边 
					covmi(1,u,l,1,n,r);
			}
		}
		else{
			ll cur=l,ans=0; 
			while(cur<=n){  
				ll num1=r+sumq(1,1,cur-1,1,n),lst=cur; 
				//将r加上前面好二分 
				cur=efsum(1,1,n,num1);
				//加r减去这段的和 
				r-=sumq(1,lst,cur-1,1,n);
				//ans+贡献 
				ans+=cur-lst;
				//超出or买不起了 
				if(mins[1]>r||cur>n) break;
				//找到第一个小于r的
				cur=minq(1,1,n,r);
			}
			cout<<ans<<'\n';
		}
	}
	return 0;
}
/*
10 6
10 10 10 6 6 5 5 5 3 1
2 3 50
2 4 10
1 3 10
2 2 36
1 4 7
2 2 17



*/
2024/10/14 11:47
加载中...