题解
回滚莫队裸题
然而我在考试的时候一直在想对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]);
}