[Ynoi2009] rprmq1 题解

考虑猫树,对第一维离线分治,类似树套树写法即可,原因是我们在一旦找到了一个点,可以从这个点往后扫描线,跑历史最大值,这个东西不容易撤销处理,所以要分治找到合适的点。

#include <bits/stdc++.h>
#define int long long
#define lid (id<<1)
#define rid (id<<1|1)
using namespace std;
const int maxn=5e4+10;
int n,m,Q,tot,ans[maxn*10],x,y,xx,yy,z,op;
struct edge{
	int x;
	int l;
	int r;
	int val;
};
struct node{
	int l;
	int r;
	int val;
};
struct edges{
	int x;
	int l;
	int r;
	int op;
};
struct nodes{
	int mx;
	int tag;
	int lazy;
	int his_mx;
	int lazy_mx;
}tree[maxn<<3];
vector<node>han[maxn<<2];
vector<edge>ll[maxn<<2],rr[maxn<<2];
vector<edges>ql[maxn<<2],qr[maxn<<2];
void push_tag(int id,long long q,long long w){
	tree[id].his_mx=max(tree[id].his_mx,tree[id].mx+w);
	tree[id].lazy_mx=max(tree[id].lazy_mx,tree[id].lazy+w);
	tree[id].lazy+=q;
	tree[id].mx+=q;
	return;
}
inline void clears(int id){
	if(tree[id].lazy||tree[id].lazy_mx){
		push_tag(lid,tree[id].lazy,tree[id].lazy_mx);
		push_tag(rid,tree[id].lazy,tree[id].lazy_mx);
		tree[id].lazy=0;
		tree[id].lazy_mx=0;
	}
	tree[id].his_mx=tree[id].mx;
	tree[id].lazy=0;
	tree[id].tag=1;
	return;
}
inline void push_down(int id){
	if(tree[id].tag){
		clears(lid);
		clears(rid);
		tree[id].tag=0;
	}
	if(tree[id].lazy_mx||tree[id].lazy){
		push_tag(lid,tree[id].lazy,tree[id].lazy_mx);
		push_tag(rid,tree[id].lazy,tree[id].lazy_mx);
		tree[id].lazy=0;
		tree[id].lazy_mx=0;
	}
	return;
}
inline void push_up(int id){
	tree[id].mx=max(tree[lid].mx,tree[rid].mx);
	tree[id].his_mx=max(tree[lid].his_mx,tree[rid].his_mx);
	return;
}
inline void add(int id,int l,int r,int q,int w,int qw){
//	if(id==1){
//		cout<<q<<' '<<w<<' '<<qw<<'\n';
//	}
	if(q<=l&&r<=w){
		tree[id].lazy+=qw;
		tree[id].mx+=qw;
		tree[id].lazy_mx=max(tree[id].lazy_mx,tree[id].lazy);
		tree[id].his_mx=max(tree[id].his_mx,tree[id].mx);
		return;
	}
	int mid=(l+r)/2;
	push_down(id);
	if(q<=mid){
		add(lid,l,mid,q,w,qw);
	}
	if(w>mid){
		add(rid,mid+1,r,q,w,qw);
	}
	push_up(id);
	return;
}
inline int query(int id,int l,int r,int q,int w){
	if(q<=l&&r<=w){
		return tree[id].his_mx;
	}
	int mid=(l+r)/2;
	push_down(id);
	if(w<=mid){
		return query(lid,l,mid,q,w);
	}
	else if(q>mid){
		return query(rid,mid+1,r,q,w);
	}
	else{
		return max(query(lid,l,mid,q,w),query(rid,mid+1,r,q,w));
	}
}
int cmp1(edge q,edge w){
	if(q.x==w.x){
		return q.val<w.val;
	}
	return q.x>w.x;
}
int cmp2(edges q,edges w){
	return q.x>w.x;
}
int cmp3(edge q,edge w){
	if(q.x==w.x){
		return q.val<w.val;
	}
	return q.x<w.x;
}
int cmp4(edges q,edges w){
	return q.x<w.x;
}
inline void adds(int id,int l,int r,int q,int w){
	if(q<=l&&r<=w){
		han[id].push_back((node){y,yy,z});
		return;
	}
	int mid=(l+r)/2;
	if(q<=mid){
		ll[id].push_back((edge){min(w,mid),y,yy,z});
		ll[id].push_back((edge){q-1,y,yy,-z});
	}
	if(w>mid){
		rr[id].push_back((edge){max(q,mid),y,yy,z});
		rr[id].push_back((edge){w+1,y,yy,-z});
	}
	if(q<=mid){
		adds(lid,l,mid,q,w);
	}
	if(w>mid){
		adds(rid,mid+1,r,q,w);
	}
	return;
}
inline void ad(int id,int l,int r,int q,int w){
	int mid=(l+r)/2;
	if(q<=mid&&w>=mid){
		ql[id].push_back((edges){q,y,yy,op});
		qr[id].push_back((edges){w,y,yy,op});
		return;
	}
	if(q<=mid){
		ad(lid,l,mid,q,w);
	}
	if(w>mid){
		ad(rid,mid+1,r,q,w);
	}
	return;
}
inline void init(int id,int l,int r){
	for(int i=0;i<han[id].size();i++){
		add(1,1,n,han[id][i].l,han[id][i].r,han[id][i].val);
	}
	int tp1,tp2,mid=(l+r)/2;
	if(ql[id].size()){
		sort(ll[id].begin(),ll[id].end(),cmp1);
		sort(ql[id].begin(),ql[id].end(),cmp2);
		tp1=-1,tp2=-1;
		clears(1);
		for(int i=mid;i>=l;i--){
			while(tp1+1<ll[id].size()&&ll[id][tp1+1].x==i){
				tp1++;
				add(1,1,n,ll[id][tp1].l,ll[id][tp1].r,ll[id][tp1].val);
			}
			while(tp2+1<ql[id].size()&&ql[id][tp2+1].x==i){
				tp2++;
				ans[ql[id][tp2].op]=max(ans[ql[id][tp2].op],query(1,1,n,ql[id][tp2].l,ql[id][tp2].r));
			}
		}
		while(tp1+1<ll[id].size()){
			tp1++;
			add(1,1,n,ll[id][tp1].l,ll[id][tp1].r,ll[id][tp1].val);
		}
	}
	if(qr[id].size()){
		sort(rr[id].begin(),rr[id].end(),cmp3);
		sort(qr[id].begin(),qr[id].end(),cmp4);
		tp1=-1,tp2=-1;
		clears(1);
		for(int i=mid;i<=r;i++){
			while(tp1+1<rr[id].size()&&rr[id][tp1+1].x==i){
				tp1++;
				add(1,1,n,rr[id][tp1].l,rr[id][tp1].r,rr[id][tp1].val);
			}
			while(tp2+1<qr[id].size()&&qr[id][tp2+1].x==i){
				tp2++;
				ans[qr[id][tp2].op]=max(ans[qr[id][tp2].op],query(1,1,n,qr[id][tp2].l,qr[id][tp2].r));
			}
		}
		while(tp1+1<rr[id].size()){
			tp1++;
			add(1,1,n,rr[id][tp1].l,rr[id][tp1].r,rr[id][tp1].val);
		}
	}
	if(l==r){
		for(int i=0;i<han[id].size();i++){
			add(1,1,n,han[id][i].l,han[id][i].r,-han[id][i].val);
		}
		return;
	}
	init(lid,l,mid);
	init(rid,mid+1,r);
	for(int i=0;i<han[id].size();i++){
		add(1,1,n,han[id][i].l,han[id][i].r,-han[id][i].val);
	}
	return;
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>m>>Q;
	for(int i=1;i<=m;i++){
		cin>>x>>y>>xx>>yy>>z;
		adds(1,1,n,x,xx);
	}
	for(int i=1;i<=Q;i++){
		tot++;
		op=i;
		cin>>x>>y>>xx>>yy;
		ad(1,1,n,x,xx);
	}
	init(1,1,n);
	for(int i=1;i<=Q;i++){
		cout<<ans[i]<<'\n';
	}
	return 0;
}
posted @ 2025-05-13 16:26  特别之处  阅读(7)  评论(0)    收藏  举报