题解 P7721【[Ynoi2007] rcn】
FunnyCreatress · · 题解
#Ynoi开始普及二维分块#
我们考虑一个广为人知的一维区间数颜色 trick:记录每个位置之前和它颜色相同的最后一个位置,查询
然而这个做法难以直接推广到二维,因为你找不到到一个合适的序。。。因此考虑降维,在横坐标上莫队,同时维护纵坐标上的前驱。先假装我们已经有了快速找到前驱后继的方法,那么我们加入/删除一个点时只会影响到
关于快速找前驱后继,实际上只需要用无增回滚就可以了。上一次被无增回滚杀还是在上一次。
于是复杂度就是
头文件已删。
int n,m,B,b[N],rb[N],pos[N],p[N],a[N],L1,L2,C,D,bv2[N],bv[L],rbv2[L],rbv[25],pre[N],nxt[N],lst[N];
ui val[N],s1[25][25],s2[25][L],s3[L][25],s4[L][L],sb[L],sv[N],ans[N*10];bool vst[N],del[N];
struct qry{int l,r,d,u,id;};vector<qry> vq[N];
bool cmp(qry u,qry v){return u.r>v.r;}
void init(){
for(int i=1;i<=D;i++)fill(s1[i],s1[i]+D+1,0),fill(s2[i],s2[i]+C+1,0);
for(int i=1;i<=C;i++)fill(s3[i],s3[i]+D+1,0),fill(s4[i],s4[i]+C+1,0);
fill(sb,sb+C+1,0),fill(sv,sv+n+1,0);
}
void update(int x,int y,ui v){
if(y==0){sb[bv2[x]]+=v,sv[x]+=v;return;}
int bx=bv[x=bv2[x]],by=bv[y=bv2[y]];
s1[bx][by]+=v,s2[bx][y]+=v,s3[x][by]+=v,s4[x][y]+=v;
}
ui query(int x,int y){
ui res=0;
for(int i=1;i<bv2[x];i++)res+=sb[i];
for(int i=rbv2[bv2[x]-1]+1;i<=x;i++)res+=sv[i];
if(!y)return res;
for(int i=rbv2[bv2[x]-1]+1;i<=x;i++)if(!del[i]&&pre[i]&&bv2[pre[i]]<bv2[y])res+=val[a[pos[i]]];
for(int i=rbv2[bv2[y]-1]+1;i<=y;i++)if(!del[i]&&nxt[i]<=x)res+=val[a[pos[i]]];
int bx=bv[x=bv2[x]],by=bv[y=bv2[y]];
for(int i=1;i<bx;i++)for(int j=1;j<by;j++)res+=s1[i][j];
for(int i=1;i<bx;i++)for(int j=rbv[by-1]+1;j<y;j++)res+=s2[i][j];
for(int i=rbv[bx-1]+1;i<x;i++)for(int j=1;j<by;j++)res+=s3[i][j];
for(int i=rbv[bx-1]+1;i<x;i++)for(int j=rbv[by-1]+1;j<y;j++)res+=s4[i][j];
return res;
}
int main(){
n=read();
for(int i=1;i<=n;i++)p[i]=read(),pos[p[i]]=i;
for(int i=1;i<=n;i++)a[i]=read();
for(int i=1;i<=n;i++)val[i]=read();
m=read(),B=n/sqrt(m);if(!B)B=1;
for(int i=1;i<=n;i++)b[i]=(i-1)/B+1;
for(int i=1;i<b[n];i++)rb[i]=i*B;rb[b[n]]=n;
L2=sqrt(n);
for(int i=1;i<=n;i++)bv2[i]=(i-1)/L2+1;
for(int i=1;i<bv2[n];i++)rbv2[i]=i*L2;rbv2[C=bv2[n]]=n;
L1=sqrt(C);
for(int i=1;i<=C;i++)bv[i]=(i-1)/L1+1;
for(int i=1;i<bv[C];i++)rbv[i]=i*L1;rbv[D=bv[C]]=C;
for(int i=1,l,r,d,u;i<=m;i++){
l=read(),r=read(),d=read(),u=read();
if(b[l]==b[r]){
for(int j=l;j<=r;j++)vst[a[j]]=0;
for(int j=l;j<=r;j++)if(p[j]>=d&&p[j]<=u)vst[a[j]]=1;
for(int j=l;j<=r;j++)if(vst[a[j]])ans[i]+=val[a[j]],vst[a[j]]=0;
}
else vq[b[l]].push_back((qry){l,r,d,u,i});
}
for(int k=1;k<=b[n];k++)if(vq[k].size()){
sort(vq[k].begin(),vq[k].end(),cmp);
fill(lst,lst+n+1,0),fill(nxt,nxt+n+1,n+1),fill(del,del+n+1,1);
for(int i=1;i<=n;i++)if(pos[i]>rb[k-1])pre[i]=lst[a[pos[i]]],lst[a[pos[i]]]=i,del[i]=0;
for(int i=1;i<=n;i++)if(pos[i]>rb[k-1]&&pre[i])nxt[pre[i]]=i;
init();
for(int i=1;i<=n;i++)if(pos[i]>rb[k-1])update(i,pre[i],val[a[pos[i]]]);
int r=n;
for(auto q:vq[k]){
while(r>q.r){
update(p[r],pre[p[r]],-val[a[r]]);
if(nxt[p[r]]!=n+1)update(nxt[p[r]],p[r],-val[a[r]]),update(nxt[p[r]],pre[p[r]],val[a[r]]),pre[nxt[p[r]]]=pre[p[r]];
if(pre[p[r]])nxt[pre[p[r]]]=nxt[p[r]];
del[p[r]]=1,r--;
}
for(int l=rb[k-1]+1;l<q.l;l++){
update(p[l],pre[p[l]],-val[a[l]]);
if(nxt[p[l]]!=n+1)update(nxt[p[l]],p[l],-val[a[l]]),update(nxt[p[l]],pre[p[l]],val[a[l]]),pre[nxt[p[l]]]=pre[p[l]];
if(pre[p[l]])nxt[pre[p[l]]]=nxt[p[l]];
del[p[l]]=1;
}
ans[q.id]=query(q.u,q.d-1)-query(q.d-1,q.d-1);
for(int l=q.l-1;l>rb[k-1];l--){
update(p[l],pre[p[l]],val[a[l]]);
if(nxt[p[l]]!=n+1)update(nxt[p[l]],pre[p[l]],-val[a[l]]),update(nxt[p[l]],p[l],val[a[l]]),pre[nxt[p[l]]]=p[l];
if(pre[p[l]])nxt[pre[p[l]]]=p[l];
del[p[l]]=0;
}
}
}
for(int i=1;i<=m;i++)printf("%u\n",ans[i]);
return 0;
}