【校內模擬】music(多重分塊)(非常規大小分塊)

簡要題意不放了,強制在線主席樹SB題一道,卡空間需要用分塊做到 O(n)O(n) 空間。


題解:

由於發下來的題解幾乎就是在口胡,我跑去UOJ羣問了一下這道題的 O(n)O(n) 空間做法,幸運地得到了myh的教育,下面的做法就來自於myh神仙。

先考慮對時間進行分塊,塊大小爲 SS,考慮把每塊中會進行修改的位置拿出來,然後把原序列中所有 n/Sn/S 的倍數的位置拿出來,以這些位置爲端點,把序列分成 O(S)O(S) 塊,每塊的大小不超過 O(n/S)O(n/S)

這樣做的好處就是,在考慮這個時間區間內的修改時,每一塊內部的變化量任何時候都是相等的,這塊內部最小值所在位置就只可能是進行修改前的最小值所在位置,並且任何一個散點到塊端點的距離不超過 O(n/S)O(n/S)

於是一次詢問需要考慮的就是 O(S)O(S) 次修改對 O(S)O(S) 個整塊的影響和 O(n/S)O(n/S) 個散點的影響。

首先考慮整塊修改,我們可以預處理出每一塊原來的最小值,然後把修改打到差分數組上,再 O(S)O(S) 將所有塊掃一遍,利用我們需要的塊更新答案。

對於散點,我們考慮處理出每個塊塊頭在當前時間塊之前的值,然後直接 O(S)O(S) 操作零散的修改算出當前塊頭的值。容易注意到兩個相鄰位置的差是 O(1)O(1) 的,於是 O(n/S)O(n/S) 把需要的散點計算出來即可。

S=O(n)S=O(\sqrt n) ,複雜度爲 O(nn)O(n\sqrt n),由於處理散點的常數有點大,SS 需要稍微縮小一點。


代碼:

#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;} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章