6722. 【2020.06.13省選模擬】T2 Arcahv

題目


正解

卡空間毒瘤題。
如果不卡空間,隨便想想就知道怎麼做(可持久化數據結構真香)……

題目相當於是選一個線段樹上的長度爲2k2^k形式的區間,首先前提是x2kx\geq 2^k(否則沒有足夠多比它小的數換進來)
無論這個區間是否包含xx,都要滿足yxy\geq大於x的數的個數。並且如果區間不包含xx,還需要滿足y>0y>0

首先將y=0y=0的情況處理出來,用個答案數組特意去存它。
於是問題的本質就是是否yxy\geq 大於x的數的個數
假如是離線,那麼可以從小到大把數加進去,在線段樹的每一層維護節點包含的最多的數字。
kk層節點包含的最多的數字的個數是2k2^k級別的,於是考慮反過來存:當節點包含的最多的數字是多少時,此時加入的數最大是多少。
2k=2n1\sum 2^k=2n-1,可以存得下。


代碼

using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N (1<<19)
int n,K,typ,m;
int h[N],re[N];
int ansy0[N];
int seg[N];
int ls[N*2],cnt[20],beg[20];
int main(){
	freopen("arcahv.in","r",stdin);
	freopen("arcahv.out","w",stdout);
	scanf("%d%d%d",&n,&K,&typ);
	for (int i=0;i<n;++i){
		scanf("%d",&h[i]),--h[i];
		re[h[i]]=i;
	}
	for (int i=n>>1;i<n;++i)
		seg[i]=max(h[(i<<1)-n],h[(i<<1|1)-n]);
	for (int l=1;l<K;++l)
		for (int i=(n>>l)-1;i>=(n>>l+1);--i)
			if (seg[i<<1]<seg[i<<1|1]){
				ansy0[seg[i<<1]]=l;
				seg[i]=seg[i<<1|1];
			}
			else{
				ansy0[seg[i<<1|1]]=l;
				seg[i]=seg[i<<1];
			}
	ansy0[seg[1]]=K;
	
	for (int l=K,p=0;l>=0;--l){
		beg[l]=p;
		p+=1<<l;
	}
	memset(seg,0,sizeof seg);
	for (int i=0;i<n;++i)
		for (int t=re[i]+n>>1,k=1;t;t>>=1,++k){
			seg[t]++;
			if (seg[t]>cnt[k]){
				ls[beg[k]+cnt[k]]=i;
				cnt[k]++;
			}
		}
	int ans=0;
	scanf("%d",&m);
	while (m--){
		int x,y;
		scanf("%d%d",&x,&y);
		x^=typ*ans,y^=typ*ans;
		--x;
		if (y==0){
			printf("%d\n",ans=ansy0[x]);
			continue;
		}
		ans=0;
		for (int k=K;k;--k){
			if (x<(1<<k)-1)
				continue;
			if (ls[beg[k]+max((1<<k)-1-y,0)]<=x){
				ans=k;
				break;
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章