[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);
}
}