简要题意不放了,强制在线主席树SB题一道,卡空间需要用分块做到 空间。
题解:
由于发下来的题解几乎就是在口胡,我跑去UOJ群问了一下这道题的 空间做法,幸运地得到了myh的教育,下面的做法就来自于myh神仙。
先考虑对时间进行分块,块大小为 ,考虑把每块中会进行修改的位置拿出来,然后把原序列中所有 的倍数的位置拿出来,以这些位置为端点,把序列分成 块,每块的大小不超过 。
这样做的好处就是,在考虑这个时间区间内的修改时,每一块内部的变化量任何时候都是相等的,这块内部最小值所在位置就只可能是进行修改前的最小值所在位置,并且任何一个散点到块端点的距离不超过 。
于是一次询问需要考虑的就是 次修改对 个整块的影响和 个散点的影响。
首先考虑整块修改,我们可以预处理出每一块原来的最小值,然后把修改打到差分数组上,再 将所有块扫一遍,利用我们需要的块更新答案。
对于散点,我们考虑处理出每个块块头在当前时间块之前的值,然后直接 操作零散的修改算出当前块头的值。容易注意到两个相邻位置的差是 的,于是 把需要的散点计算出来即可。
取 ,复杂度为 ,由于处理散点的常数有点大, 需要稍微缩小一点。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
using std::cin;
using std::cerr;
using std::cout;
cs int N=2e5+7;
cs int S=250,M=N/S+7;
int n,m,len;
int a[N],t[N];
int id[N],rk[N];
int b[N],bn;
int *mn[N],*bg[N];
int bl[N],*nd[N];
int dif[N];
int tmp[N],ct;
void Main(){
scanf("%d%d",&n,&m);len=n-m+1;
for(int re i=0;i<n;++i)
cin>>a[i],b[i]=a[i],id[i]=i;
std::sort(b,b+n);bn=std::unique(b,b+n)-b;
std::sort(id,id+n,
[](int i,int j){return a[i]<a[j];});
for(int re i=0;i<n;++i)rk[id[i]]=i;
for(int re i=0;i<n;++i)
t[std::lower_bound(b,b+bn,a[id[i]])-b]=i;
for(int re i=0;i<n;i+=S){
for(int re j=0;j<len;j+=len/S+1)tmp[ct++]=j;
for(int re j=i;j<i+S&&j<n;++j){
tmp[ct++]=std::min(id[j]+1,len);
tmp[ct++]=std::max(0,id[j]-m+1);
}tmp[ct++]=len;std::sort(tmp,tmp+ct);
ct=std::unique(tmp,tmp+ct)-tmp;
int bid=i/S;bl[bid]=ct;
nd[bid]=new int[ct];
mn[bid]=new int[ct];bg[bid]=new int[ct];
memcpy(nd[bid],tmp,sizeof(int)*ct);
for(int j=0,val=0,nw=0;j<=len;++j){
val+=dif[j];
if(nw<ct&&j==nd[bid][nw]){
bg[bid][nw]=val;mn[bid][nw]=val;++nw;
}else mn[bid][nw-1]=std::min(mn[bid][nw-1],val);
}
for(int re j=i;j<i+S&&j<n;++j){
--dif[std::min(id[j]+1,len)];
++dif[std::max(0,id[j]-m+1)];
}ct=0;
}memset(dif,0,sizeof dif);
int Q,ans=0;scanf("%d",&Q);
while(Q--){
int l,r,x;scanf("%d%d%d",&l,&r,&x);--l,--r;
x^=ans;int T=std::lower_bound(b,b+bn,x)-b;
if(!T){cout<<(ans=0)<<"\n";continue;}
T=t[T-1];int pl,pr,bid=T/S;ans=1e9;
pl=std::upper_bound(nd[bid],nd[bid]+bl[bid],l)-nd[bid]-1;
pr=std::upper_bound(nd[bid],nd[bid]+bl[bid],r)-nd[bid]-1;
if(pl==pr){
int val=bg[bid][pl];
for(int re i=bid*S;i<=T;++i)
if(id[i]-m+1<=nd[bid][pl]&&nd[bid][pl]<=id[i])
++val;
for(int re i=nd[bid][pl];i<=r;++i){
if(l<=i)ans=std::min(ans,val);
if(rk[i]<=T)--val;
if(i+m<n&&rk[i+m]<=T)++val;
}
}else {
int val=bg[bid][pl];
for(int re i=bid*S;i<=T;++i)
if(id[i]-m+1<=nd[bid][pl]&&nd[bid][pl]<=id[i])
++val;
for(int re i=nd[bid][pl];i<nd[bid][pl+1];++i){
if(l<=i)ans=std::min(ans,val);
if(rk[i]<=T)--val;
if(i+m<n&&rk[i+m]<=T)++val;
}val=bg[bid][pr];
for(int re i=bid*S;i<=T;++i)
if(id[i]-m+1<=nd[bid][pr]&&nd[bid][pr]<=id[i])
++val;
for(int re i=nd[bid][pr];i<=r;++i){
ans=std::min(ans,val);
if(rk[i]<=T)--val;
if(i+m<n&&rk[i+m]<=T)++val;
}for(int re i=bid*S;i<=T;++i){
--dif[std::min(id[i]+1,len)];
++dif[std::max(0,id[i]-m+1)];
}val=0;
for(int re i=0;i<pr;++i){
val+=dif[nd[bid][i]];
if(i>pl)ans=std::min(ans,val+mn[bid][i]);
}
for(int re i=bid*S;i<=T;++i){
dif[std::min(id[i]+1,len)]=0;
dif[std::max(0,id[i]-m+1)]=0;
}
}cout<<ans<<"\n";
}
}
inline void file(){
#ifdef zxyoi
freopen("music.in","r",stdin);
freopen("music.out","w",stdout);
#endif
}signed main(){file();Main();return 0;}