[SCOI2016]美味

\(\text{Solution}\)

发现用\(trie\)不好解决\(a_i + x\)的这一步。
考虑用线段树模拟\(trie\),对于第\(i\)位,在区间\([0,2^i - 1]\)的数这一位为\(0\),在区间\([2^i,2^{i + 1} - 1]\)的数这一位为\(1\)
对于\(a_i + x\),相当于将区间向左移动了\(x\)位。
用主席树维护即可。

\(\text{Code}\)

#include<cstdio>
using namespace std;
const int N = 1e5;
int n,m,rt[N * 3],size;

struct tree{int ls,rs,s;}f[(N + 5) * 50];
void update(int &p1,int p2,int l,int r,int u)
{
	p1 = ++size,f[p1] = f[p2],f[p1].s++;
	if (l == r) return; int mid = l + r >> 1;
	if (u <= mid) update(f[p1].ls,f[p2].ls,l,mid,u);
	else update(f[p1].rs,f[p2].rs,mid + 1,r,u);
}
int query(int p1,int p2,int l,int r,int L,int R)
{
	if (r < L || l > R) return 0;
	if (L <= l && r <= R) return f[p1].s - f[p2].s;
	int mid = l + r >> 1,tmp = 0;
	if (L <= mid) tmp = query(f[p1].ls,f[p2].ls,l,mid,L,R);
	if (R > mid) tmp += query(f[p1].rs,f[p2].rs,mid + 1,r,L,R);
	return tmp;
}
int main()
{
	scanf("%d%d",&n,&m);
	for (int i = 1,q; i <= n; i++) scanf("%d",&q),update(rt[i],rt[i - 1],0,N,q);
	for (int i = 1,b,x,q,p; i <= m; i++)
	{
		scanf("%d%d%d%d",&b,&x,&q,&p);
		int ans = 0;
		for (int j = 17; j >= 0; j--)
		{
			int k = (b >> j) & 1,l1 = ans - x,r1 = ans + (1 << j) - 1 - x;
			int l2 = r1 + 1,r2 = r1 + (1 << j);
			if (k && !query(rt[p],rt[q - 1],0,N,l1,r1)) ans += (1 << j);
			if (!k && query(rt[p],rt[q - 1],0,N,l2,r2)) ans += (1 << j); 
		}
		printf("%d\n",ans ^ b);
	}
}
posted @ 2022-04-03 16:33  RiverSheep  阅读(25)  评论(1编辑  收藏  举报