【省選模擬】20/04/20 music (分塊)(卡空間)

  • 題意:
    每個點的權值爲向後 mm 箇中 x\le x 的個數,給定 l,r,xl,r,x 求最小權值,強制在線,空間 n2e5,70MB,5sn\le 2e5,70MB,5s

  • 如果不強制在線的話,考慮按 aia_i 加入答案算貢獻,線段樹維護就做完了
    如果不卡空間的話,主席樹就做完了
    聽大神 ldxldx 講了過後就會了下面空間 O(n)O(n),時間 O(nn)O(n\sqrt n) 的做法

  • 考慮修改用差分表示,那麼就是一個點 +1,一個點 - 1,維護前綴最大值,那麼一個點最多被修改 2 次
    注意到這樣的話一個大小爲 SS 的塊的狀態數是 S2S*2 的,直接記下即可
    需要維護塊的每個時間的和,塊的前綴最大值
    散塊查詢可以先求出塊頭的答案,然後 O(1)O(1) 差分遞推
    現在的問題是要找到每個塊對應的時間,本來想 O(nlogn)O(\sqrt {n\log n}) 走人的,結果又被 ldxldx 教育了
    考慮一長爲 2n2n 的序列,每個點有個顏色,顏色數 n\sqrt n
    那麼直接繼續分塊,預處理每種顏色在 n\sqrt n 的時間處的取值就可以嚴格 n\sqrt n
    分塊怎麼套都是 n\sqrt n

#include<bits/stdc++.h>
#define cs const
#define pb push_back
using namespace std;
namespace IO{
	cs int Rlen=1<<20|1;
	inline char gc(){
		static char buf[Rlen],*p1,*p2;
		(p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin));
		return p1==p2?EOF:*p1++;
	}
	int read(){
		int x=0; char c=gc(); bool f=false;
		while(!isdigit(c)) f=c=='-', c=gc();
		while(isdigit(c)) x=(((x<<2)+x)<<1)+(c^48), c=gc();
		return f?-x:x;
	}
} using namespace IO;
typedef pair<int, int> pi;
typedef vector<int> poly;
cs int N = 2e5 + 50, M = 550;
cs int INF = 1e9 + 7;
int n, S, m, q, T, a[N], blk[N];
int L[M], R[M], cnt;
int ct[M], s[N], ps[M];
poly mn[M], sm[M];
namespace sub{
cs int N = ::N << 1;
cs int M = 850;
struct node{ int a, b, c; };
bool operator < (cs node &a, cs node &b){ return a.a < b.a; }
node c[N]; int len, S, ct;
int p[M][M], L[M], R[M]; int blk[N];
void pre_work(){
	S=sqrt(len); 
	for(int i=1; i<=len; i++) blk[i]=(i-1)/S+1;
	for(int i=1; i<=len; i+=S) ++ct, L[ct]=i, R[ct]=i+S-1; R[ct]=n;
	static int tmp[M]; // current
	for(int i=1,t=1; i<=len; i++){
		node nw = c[i]; tmp[nw.b]=nw.c;
		if(i==R[t]){ for(int j=1; j<=cnt; j++) p[j][t]=tmp[j]; ++t; }
	}
}
void work(int x){
	int t = lower_bound(c+1, c+len+1, (node){x,0,0}) - (c+1), b = blk[t];
	for(int i=1; i<=cnt; i++) ps[i]=p[i][b-1];
	for(int i=L[b]; i<=t; i++){ node nw = c[i]; ps[nw.b]=nw.c; }
}
}
void Add(int p, int v, int a){
	if(p>n) return; 
	int b = blk[p]; int nw = INF;
	sm[b].pb(sm[b][ct[b]] + v); ++ct[b]; 
	for(int i=p; i<=R[b]; i++) s[i]+=v;
	for(int i=L[b]; i<=R[b]; i++) nw=min(nw,s[i]);
	mn[b].pb(nw); sub :: c[++sub::len] = {a,b,ct[b]};
}
int subwork(int v, int S, int l, int r){
	int as = INF, now = v;
	for(int i=S; i<=r; i++){
		if(i>=l) as = min(as,now);
		now -= (i>0&&a[i]<T); now += (a[i+m]<T);
	} return as;
}
int work(int l, int r){
	int as=INF, Sm=0, u=0, v=0;
	for(int i=1; i<=cnt; i++){
		if(i==blk[l]) u=Sm;
		if(i==blk[r]){ v=Sm; break; }
		if(l<=L[i]&&R[i]<=r) as=min(as,Sm+mn[i][ps[i]]);
		Sm+=sm[i][ps[i]]; 
	} 
	if(blk[l] == blk[r]) return min(as, subwork(u,L[blk[l]]-1,l,r));
	if(l>L[blk[l]]) as = min(as, subwork(u,L[blk[l]]-1,l,R[blk[l]]));
	as = min(as, subwork(v,L[blk[r]]-1,L[blk[r]],r)); return as;
}
int main(){
	#ifdef FSYolanda
	freopen("music.in","r",stdin);
	freopen("music.out","w",stdout);
	#endif
	n=read(), m=read(); S=sqrt(n); static int id[N]; 
	for(int i=1; i<=n; i++) a[i]=read(), id[i]=i;
	sort(id+1, id+n+1, [](cs int &i, cs int &j){ return a[i] < a[j]; });
	
	blk[0]=1; for(int i=1; i<=n; i++) blk[i]=(i-1)/S+2; ++cnt;
	for(int i=1; i<=n; i+=S) ++cnt, L[cnt]=i, R[cnt]=i+S-1; R[cnt]=n;
	for(int i=1; i<=cnt; i++) sm[i].pb(0), mn[i].pb(0);
	for(int i=1; i<=n; i++){
		int u=id[i];
		Add(max(0,u-m+1),1,a[u]); Add(u+1,-1,a[u]);
	} sub :: pre_work();
	q=read(); int as=0;
	while(q--){
		int l=read(), r=read(); T=read()^as;
		sub :: work(T); 
		cout << (as=work(l,r)) << '\n';
	} return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章