[SCOI2016]美味

题目

[\(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);
	}
} 
posted @ 2020-11-06 20:32  leiyuanze  阅读(98)  评论(0编辑  收藏  举报