luogu P3293 [SCOI2016]美味

背景:

只有一天的假期 . . . ... ...

题意:

给出 n n n个数 a i a_i ai,多组询问,每一次给出 x , b , l , r x,b,l,r x,b,l,r,求 b  xor  ( a i + x ) b\text{ xor }(a_i+x) b xor (ai+x)的最大值,其中 i ∈ [ l , r ] i∈[l,r] i[l,r]

思路:

你考虑当 x = 0 x=0 x=0时就是 01Trie \text{01Trie} 01Trie了。
但是这一题的 x x x有点坑啊。
本质上还是贪心,因为每一位之间不会影响,你要使高位尽可能为 1 1 1即可。
开启懒人模式(https://www.cnblogs.com/Yangrui-Blog/p/9683222.html):
在这里插入图片描述
我是真的没想到啊( tcl \text{tcl} tcl)。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define INF int(1e5)
using namespace std;
	int ls[8000010],rs[8000010],root[200010],tot[8000010];
	int n,m,len=0,ans;
void change(int last,int &now,int x,int l,int r)
{
	if(!now) now=++len;
	tot[now]=tot[last]+1;
	if(l==r) return;
	int mid=(l+r)/2;
	if(x<=mid)
	{
		rs[now]=rs[last];
		change(ls[last],ls[now],x,l,mid);
	}
	else
	{
		ls[now]=ls[last];
		change(rs[last],rs[now],x,mid+1,r);
	}
}
int solve(int x,int y,int l,int r,int target_l,int target_r)
{
	if(target_l<=l&&r<=target_r) return tot[y]-tot[x];
	int mid=(l+r)/2,sum=0;
	if(target_l<=mid) sum+=solve(ls[x],ls[y],l,mid,target_l,target_r);
	if(mid<target_r) sum+=solve(rs[x],rs[y],mid+1,r,target_l,target_r);
	return sum;
}
bool check(int x,int y,int target_l,int target_r)
{
	target_l=max(target_l,0),target_r=min(target_r,INF);
	if(target_l>target_r) return false;
	return solve(root[x-1],root[y],0,INF,target_l,target_r);
}
int main()
{
	int b,x,l,r;
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&x);
		change(root[i-1],root[i],x,0,INF);
	}
	for(int i=1;i<=m;i++)
	{
		ans=0;
		scanf("%d %d %d %d",&b,&x,&l,&r);
		for(int j=17;j>=0;j--)
		{
			int now=ans+((1^((b>>j)&1))<<j);
			if(check(l,r,now-x,now+(1<<j)-x-1)) ans=now; else ans+=(((b>>j)&1)<<j);
		}
		printf("%d\n",ans^b);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值