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