簡要題意不放了,強制在線主席樹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;}