题解

回滚莫队裸题

然而我在考试的时候一直在想对vl,vr进行莫队,脑子进水了。。

直接对l,r进行莫队,就变成了线段树单点加,区间求最大值

这样的复杂度是O(nsqrt(q)*logm+q*logm)的

我们可以根号平衡一下,用分块set来实现O(1)插入,O(sqrt(n))查询(简单实现)

但是我们发现这样会有问题

当我们的莫队删除一个点的时候,最大值需要重新计算这样就会退化为sqrt(m),时间复杂度高达O(n*sqrt(q)*sqrt(m)+q*sqrt(m))

我们需要改进

稍加思考,发现这个问题就像并查集、线性基在线段树分治的时候一样,不支持删除,但是我们可以进行撤回操作

对于左端点在同一个块的询问,我们可以把他们分为一组

我们一组一组地来求解问题

如果当前的右端点与左端点同块,就直接暴力(注意是l,r同块,vl,vr不一定同块,坑了我好久)

否则就可以移动先莫队的右端点,把在块外的点加进分块set,最后加入在块内的点并记录分块set的值变化

回答询问后利用该记录撤回块内加入的点即可

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 150005
#define D 400
#define LL long long
int n,m,Q;
int a[N],b[N];
int bel[N],L[N],R[N];
LL tong[N],mx[N/D+5],tmp[N/D+5];
struct node{
	int l,r,vl,vr,id;
	bool operator < (const node &t)const{
		return bel[l]<bel[t.l]||(bel[l]==bel[t.l]&&r<t.r);
	}
}q[N];
LL ans[N];
void add(int i)
{
	int t=a[i];
	tong[t]+=b[i];
	mx[bel[t]]=max(mx[bel[t]],tong[t]);
}
void query(int k)
{
	int bl=bel[q[k].vl],br=bel[q[k].vr],o;LL ret=0;
	if(bl==br){for(o=q[k].vl;o<=q[k].vr;o++)ret=max(ret,tong[o]);}
	else{
		for(o=q[k].vl;o<=R[bl];o++)ret=max(ret,tong[o]);
		for(o=bl+1;o<br;o++)ret=max(ret,mx[o]);
		for(o=L[br];o<=q[k].vr;o++)ret=max(ret,tong[o]);
	}
	ans[q[k].id]=ret;
}
int main()
{
	int i,j,k,o,l,r;
	scanf("%d%d%d",&n,&m,&Q);
	memset(L,0x3f,sizeof(L));
	for(i=1;i<=n;i++)scanf("%d",&a[i]);
	for(i=1;i<=n;i++)scanf("%d",&b[i]);
	for(i=1;i<=max(n,m);i++){
		bel[i]=(i-1)/D+1;
		L[bel[i]]=min(L[bel[i]],i);
		R[bel[i]]=max(R[bel[i]],i);
	}
	for(i=1;i<=Q;i++){
		scanf("%d%d%d%d",&q[i].l,&q[i].r,&q[i].vl,&q[i].vr);
		q[i].id=i;
	}
	sort(q+1,q+Q+1);
	for(i=j=1;i<=Q;i++){
		if(bel[q[i].l]!=bel[q[i+1].l]){
			memset(tong,0,sizeof(tong));
			memset(mx,0,sizeof(mx));
			int id=bel[q[i].l];
			r=R[id];
			for(k=j;k<=i;k++){
				if(q[k].r<=R[id]){
					for(o=q[k].l;o<=q[k].r;o++){
						tong[a[o]]+=b[o];
						if(q[k].vl<=a[o]&&a[o]<=q[k].vr)
							ans[q[k].id]=max(ans[q[k].id],tong[a[o]]);
					}
					for(o=q[k].l;o<=q[k].r;o++)tong[a[o]]-=b[o];
					continue;
				}
				while(r<q[k].r){r++;add(r);}
				memcpy(tmp,mx,sizeof(mx));
				for(l=R[id];l>=q[k].l;l--)add(l);
				query(k);
				for(l=R[id];l>=q[k].l;l--)tong[a[l]]-=b[l];
				memcpy(mx,tmp,sizeof(tmp));
			}
			j=i+1;
		}
	}
	for(i=1;i<=Q;i++)
		printf("%lld\n",ans[i]);
}