题解 CF543E 【Listening to Music】

x义x

2020-07-05 08:14:45

Solution

怎么都是主席树卡空间做法……来个官方的分块解法吧。 一开始的思路很简单,首先转化成求大于等于 $q$ 的元素数目(个人感觉更好理解?),那么就是从大到小枚举 $a_i$,然后对 $[i-m+1,i]$ 区间加一,询问就是区间求 max。但是这题强制在线+卡空间,所以我们考虑分块。 考虑对序列分块再对修改分块,对修改分块的意思就是我们只存 $\sqrt n$ 个版本。整块的修改很好搞,和普通序列分块一样,整块打tag边角暴力修改。 考虑剩下的 $\sqrt n$ 个边角修改。如果按上面的方法 $O(\sqrt n)$ 修改那必然无法接受。整块依然可以差分打tag,对于两个边角块我们直接预处理它的 max 覆盖掉原来的答案。(此处 max 不考虑边角修改的整块 tag 的贡献,但是考虑整块修改的整块 tag 的贡献,因为查询的时候我们会把它和边角修改的整块 tag 加一起,我被这个迷惑了很久) 询问就很好搞了,还是边角暴力整块查tag。 代码里每个版本除了整块 max 只存了每一块开头的元素,其实显然是和每一个元素都存等价的。 有些细节还是需要注意的,有需要的话建议多读几遍代码。(这个鬼东西真的能读吗?) 不出意外喜提最劣解。代码如下: ```cpp #include<bits/stdc++.h> using namespace std; const int maxN=200005,LEN=450; int N,M,Q,len,cntb; //len 块长,cntb 块数 int bg[LEN],ed[LEN]; //bg 块开头编号,ed 块结尾编号 int inb[maxN]; //inb 元素处在的块的编号 int A[maxN],id[maxN]; bool cmp(int a,int b){ return A[a]>A[b]; } int Lpos[maxN],Rpos[maxN]; //修改操作的左右端点编号 int Linb[maxN],Rinb[maxN]; //修改操作的左右端点所在块编号 int Lans[maxN],Rans[maxN]; //修改操作的左右端点所在块的答案 int ans[LEN],val[maxN],lzy[LEN]; int ANS[LEN][LEN],bgval[LEN][LEN]; void init(){ scanf("%d%d",&N,&M); len=sqrt(N); for(int i=1;i<=N;i++) inb[i]=(i-1)/len+1,bg[inb[i]]=(bg[inb[i]]?bg[inb[i]]:i),ed[inb[i]]=i;cntb=inb[N]; for(int i=1;i<=N;i++) scanf("%d",&A[i]),id[i]=i; sort(id+1,id+N+1,cmp); for(int i=1;i<=N;i++){ Lpos[i]=max(1,id[i]-M+1),Rpos[i]=id[i]; Linb[i]=inb[Lpos[i]],Rinb[i]=inb[Rpos[i]]; if(inb[i]!=inb[i-1]){ //存储版本,pushdown tag,保证 LansRans 有完整修改的 tag 而没有边角修改的 tag for(int j=1;j<=N;j++) val[j]+=lzy[inb[j]]; for(int j=1;j<=cntb;j++) ANS[inb[i]][j]=ans[j],bgval[inb[i]][j]=val[bg[j]],lzy[j]=0; } //修改 if(Linb[i]==Rinb[i]){ for(int j=Lpos[i];j<=Rpos[i];j++) val[j]++,ans[inb[j]]=max(ans[inb[j]],val[j]+lzy[inb[j]]); for(int j=bg[Linb[i]];j<=ed[Linb[i]];j++) Lans[i]=max(Lans[i],val[j]); } else{ for(int j=Lpos[i];j<=ed[Linb[i]];j++) val[j]++,ans[inb[j]]=max(ans[inb[j]],val[j]+lzy[inb[j]]); for(int j=Linb[i]+1;j<=Rinb[i]-1;j++) lzy[j]++,ans[j]++; for(int j=bg[Rinb[i]];j<=Rpos[i];j++) val[j]++,ans[inb[j]]=max(ans[inb[j]],val[j]+lzy[inb[j]]); for(int j=bg[Linb[i]];j<=ed[Linb[i]];j++) Lans[i]=max(Lans[i],val[j]); for(int j=bg[Rinb[i]];j<=ed[Rinb[i]];j++) Rans[i]=max(Rans[i],val[j]); } } } int lstans; int brute_query(int L,int R,int bid,int tmp,int q){ int ANS=0; for(int i=bg[bid];i<L;i++) tmp+=(A[i+M]>=q)-(A[i]>=q); for(int i=L;i<=R;i++) ANS=max(ANS,tmp),tmp+=(A[i+M]>=q)-(A[i]>=q); return ANS; } int main(){ init(); scanf("%d",&Q); while(Q--){ int QL,QR,QQ,QX;scanf("%d%d%d",&QL,&QR,&QQ);QQ^=lstans; A[N+1]=QQ;QX=upper_bound(id+1,id+N+1,N+1,cmp)-id-1; memset(lzy,0,sizeof(lzy)); for(int i=1;i<=cntb;i++) ans[i]=ANS[inb[QX]][i]; int bgvalL=bgval[inb[QX]][inb[QL]],bgvalR=bgval[inb[QX]][inb[QR]]; for(int i=bg[inb[QX]];i<=QX;i++){ ans[Linb[i]]=Lans[i]; if(Linb[i]!=Rinb[i]) ans[Rinb[i]]=Rans[i],lzy[Linb[i]+1]++,lzy[Rinb[i]]--; if(Lpos[i]<=bg[inb[QL]]&&bg[inb[QL]]<=Rpos[i]) bgvalL++; if(Lpos[i]<=bg[inb[QR]]&&bg[inb[QR]]<=Rpos[i]) bgvalR++; } for(int i=1;i<=cntb;i++) lzy[i]+=lzy[i-1]; int ANS=0; if(inb[QL]==inb[QR]) ANS=brute_query(QL,QR,inb[QL],bgvalL,QQ); else{ ANS=max(ANS,brute_query(QL,ed[inb[QL]],inb[QL],bgvalL,QQ)); ANS=max(ANS,brute_query(bg[inb[QR]],QR,inb[QR],bgvalR,QQ)); for(int i=inb[QL]+1;i<=inb[QR]-1;i++) ANS=max(ANS,ans[i]+lzy[i]); } printf("%d\n",lstans=M-ANS); } return 0; } ```