P9494 「SFCOI-3」进行一个走的行 思考--zhengjun

发布时间 2023-08-05 20:01:17作者: A_zjzj

平衡树好题。

考虑整体直接模拟操作。

  • l -1 x

    • \(x\in[1,l]\):不用动;
    • \(x\in(l,2l]\):整体减去 \(l\) 之后暴力插回去;
    • \(x\in(2l,+\infty)\):整体减 \(l\) 与第一段合并。
  • l r x:区间加即可

复杂度显然是 2log 的,考虑重新插入一次的时候值会减半。

代码

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=2e5+10;
int n,m,a[N],b[N],c[N];
vector<pair<int,int> >o[N];
vector<int>q[N];
mt19937 rnd(time(0));
struct node{
	int fa,ls,rs,rnd,val,laz;
	ll ans,tag;
}t[N];
int root;
void pushup(int rt){
	if(t[rt].ls)t[t[rt].ls].fa=rt;
	if(t[rt].rs)t[t[rt].rs].fa=rt;
	t[rt].fa=0;
}
void pushadd(int rt,int x){
	if(rt)t[rt].val+=x,t[rt].laz+=x;
}
void pushans(int rt,ll x){
	if(rt)t[rt].ans+=x,t[rt].tag+=x;
}
void pushdown(int rt){
	if(t[rt].laz){
		pushadd(t[rt].ls,t[rt].laz);
		pushadd(t[rt].rs,t[rt].laz);
		t[rt].laz=0;
	}
	if(t[rt].tag){
		pushans(t[rt].ls,t[rt].tag);
		pushans(t[rt].rs,t[rt].tag);
		t[rt].tag=0;
	}
}
void split(int rt,int val,int &x,int &y){
	if(!rt){
		x=y=0;return;
	}
	pushdown(rt);
	if(val<t[rt].val)y=rt,split(t[rt].ls,val,x,t[rt].ls);
	else x=rt,split(t[rt].rs,val,t[rt].rs,y);
	pushup(rt);
}
int merge(int x,int y){
	if(!x||!y)return x|y;
	if(t[x].rnd<t[y].rnd){
		pushdown(x);
		t[x].rs=merge(t[x].rs,y);
		return pushup(x),x;
	}else{
		pushdown(y);
		t[y].ls=merge(x,t[y].ls);
		return pushup(y),y;
	}
}
void insert(int x,int &y){
	if(!x)return;
	pushdown(x);
	insert(t[x].ls,y);
	insert(t[x].rs,y);
	int r1,r2;
	split(y,t[x].val,r1,r2);
	t[x].fa=t[x].ls=t[x].rs=0;
	y=merge(merge(r1,x),r2);
}
ll ans[N];
void update(int rt){
	if(t[rt].fa)update(t[rt].fa);
	pushdown(rt);
}
ll query(int x){
	update(x);
	return t[x].ans;
}
int main(){
	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%d%d%d",&a[i],&b[i],&c[i]);
	for(int i=1,l,r,x;i<=m;i++){
		scanf("%d%d%d",&l,&r,&x);
		o[l].push_back({x,i});
		q[r].push_back(i);
	}
	for(int i=1;i<=n;i++){
		for(auto p:o[i]){
			int x,id,r1,r2;
			tie(x,id)=p;
			t[id]={0,0,0,(int)rnd(),x,0,0,0};
			split(root,x,r1,r2);
			root=merge(merge(r1,id),r2);
		}
		if(~b[i]){
			if(a[i]<=b[i]){
				int r1,r2,r3;
				split(root,b[i],r2,r3);
				split(r2,a[i]-1,r1,r2);
				pushans(r2,c[i]);
				root=merge(merge(r1,r2),r3);
			}
		}else{
			int r1,r2,r3;
			split(root,a[i],r1,r2);
			pushans(r2,c[i]);
			pushadd(r2,-a[i]);
			split(r2,a[i],r2,r3);
			insert(r2,r1);
			root=merge(r1,r3);
		}
		for(int x:q[i])ans[x]=query(x);
	}
	for(int i=1;i<=m;i++)printf("%lld\n",ans[i]);
	return 0;
}