luogu P3293 [SCOI2016]美味
Posted smyjr
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu P3293 [SCOI2016]美味相关的知识,希望对你有一定的参考价值。
异或最大值应该是要用(trie)树,从高位往低位贪心,虽然这里询问区间的数都要加上(x),但是仍然可以利用这个思想
从高往低位考虑,我们要找一个加上(x)后当前二进制位(j)不等于(b)的当前位的数,假设(b)当前位为0,我们就要现在找个数加上(x)后当前位(j)为1,记之前选出的数为(ans),那么我们就要找一个在([ans+(1<<j)-x,ans+(1<<j)-(1<<j)-1-x])区间内的数;如果(b)当前位为1,那么取值范围为([ans-x,ans-(1<<j)-1-x]).如果有这个数,那么(ans)当前位(j)就可以等于(b)当前位(xor 1),否则就反过来
这个操作可以用主席树查询某区间的数出现次数的操作实现
#include<bits/stdc++.h>
#define LL long long
#define il inline
#define re register
#define db double
#define eps (1e-7)
using namespace std;
const int N=500000+10;
const LL inf=1ll<<45;
il LL rd()
{
re LL x=0,w=1;re char ch=0;
while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*w;
}
#define mid ((l+r)>>1)
int s[N*20],ch[N*20][2],rt[N],tt;
int n,m,kk,L,R,a[N];
il void inst(int p)
{
rt[p]=++tt;
int o1=rt[p],o2=rt[p-1],l=0,r=n;
s[o1]=s[o2]+1;
do
{
if(a[p]<=mid)
{
ch[o1][0]=++tt,ch[o1][1]=ch[o2][1];
o1=ch[o1][0],o2=ch[o2][0],r=mid;
}
else
{
ch[o1][0]=ch[o2][0],ch[o1][1]=++tt;
o1=ch[o1][1],o2=ch[o2][1],l=mid+1;
}
s[o1]=s[o2]+1;
}
while(l<r);
}
int quer(int o1,int o2,int l,int r,int ll,int rr)
{
if(ll<=l&&r<=rr) return s[o1]-s[o2];
int an=0;
if(ll<=mid) an+=quer(ch[o1][0],ch[o2][0],l,mid,ll,rr);
if(rr>mid) an+=quer(ch[o1][1],ch[o2][1],mid+1,r,ll,rr);
return an;
}
bool ok(int l,int r,int ll,int rr)
{
ll=max(ll,0),rr=min(rr,n);
return ll<=rr?quer(rt[r],rt[l-1],0,n,ll,rr):0;
}
int q;
int main()
{
///no O2
m=rd(),q=rd();
for(int i=1;i<=m;i++) n=max(n,a[i]=rd());
for(int i=1;i<=m;i++) inst(i);
while(q--)
{
int b=rd(),x=rd(),ll=rd(),rr=rd(),ans=0;
for(int i=17;i>=0;i--)
{
int nw=ans|(((b>>i&1)^1)<<i);
if(ok(ll,rr,nw-x,nw+(1<<i)-1-x)) ans=nw;
else ans|=(b>>i&1)<<i;
}
printf("%d
",ans^b);
}
return 0;
}
以上是关于luogu P3293 [SCOI2016]美味的主要内容,如果未能解决你的问题,请参考以下文章