[SCOI2016]美味
题目
分析
我们需要 \([l,r]\) 中的 \(a_i + x\) 满足它异或 \(b\) 最大
那么我们贪心的考虑 \(ans = a_i + x\)
对于 \(b\) 的第 \(i\),如果是 \(1\),那么我们希望能找到一个 \(a_i + x\) 使得它的第 \(i\) 位为 \(1\),后面位不限,前面为满足之前贪心的 \(ans\)
否则就得 \(ans += (1 << i)\)
那么这个 \(a_i + x\) 的范围就是 \([ans ,ans + (1<<i) - 1]\)
把 \(x\) 移过去就是 \(a_i\) 的范围,主席树弄出区间判断有没有即可
如果为 \(0\) 的话,同理可求 \(a_i\) 的范围
\(Code\)
#include<cstdio>
using namespace std;
const int N = 2e5 + 5;
int n , m , mx , size , rt[N] , a[N];
struct segment{
int ls , rs , s;
}seg[N << 5];
int update(int x , int l , int r , int rt)
{
int o = ++size; seg[o] = seg[rt] , seg[o].s = seg[rt].s + 1;
if (l == r && l == x) return o;
int mid = (l + r) >> 1;
if (x <= mid) seg[o].ls = update(x , l , mid , seg[rt].ls);
if (x > mid) seg[o].rs = update(x , mid + 1 , r , seg[rt].rs);
return o;
}
int query(int u , int v , int l , int r , int tl , int tr)
{
int o = seg[v].s - seg[u].s;
if (tr < l || tl > r || !o) return 0;
if (tl <= l && r <= tr) return o;
int mid = (l + r) >> 1;
return query(seg[u].ls , seg[v].ls , l , mid , tl , tr) + query(seg[u].rs , seg[v].rs , mid + 1 , r , tl , tr);
}
int main()
{
scanf("%d%d" , &n , &m);
for(register int i = 1; i <= n; i++) scanf("%d" , a + i) , mx = mx < a[i] ? a[i] : mx;
for(register int i = 1; i <= n; i++) rt[i] = update(a[i] , 0 , mx , rt[i - 1]);
int b , x , l , r , ans;
while (m--)
{
scanf("%d%d%d%d" , &b , &x , &l , &r);
ans = 0;
for(register int i = 20; i >= 0; i--)
{
if (b & (1 << i) && !query(rt[l - 1] , rt[r] , 0 , mx , ans - x , ans + (1 << i) - 1 - x))
ans += (1 << i);
if (!(b & (1 << i)) && query(rt[l - 1] , rt[r] , 0 , mx , ans + (1 << i) - x , ans + (1 << i + 1) - 1 - x))
ans += (1 << i);
}
printf("%d\n" , ans ^ b);
}
}