[luogu P3293] [SCOI2016]美味
\(\text{Problem}\):题目链接
\(\text{Solution}\):
和异或有关,考虑一些和 \(01\) \(\text{Trie}\) 有关的性质。对于 \(a_{i}\) \(xor\) \(y\),假设 \(y\) 已经确定,则选 \(x\) 时要从高到低的贪心使得 \(a_{i}\) 的每一位和 \(y\) 不同。考虑为什么贪心正确。假设 \(dep\) 是 \(a_{i}\) 和 \(y\) 二进制下同一位置不同的最高位,则选择第 \(dep\) 位与 \(y\) 不同的 \(a_{i}\) 是最优的(\(2^{n}>\sum\limits_{i=0}^{n-1}2^{i}\))。
现在考虑 \((a_{i}+x)\) \(xor\) \(y\) 最大,则可以把 \((a_{i}+x)\) 看作是一个整体。又存在对 \(a_{i}\) 选取的限制,所以要在区间 \([L,R]\) 中查询是否有使得 \((a_{i}+x)\) 与 \(y\) 的当前二进制位不同的数。这个我们可以用主席树解决。
\(\text{Code}\):
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
#include <vector>
#include <stack>
#include <map>
#include <bitset>
#define ri register
#define inf 0x7fffffff
#define E (1)
#define mk make_pair
//#define int long long
//#define double long double
using namespace std; const int N=200010;
inline int read()
{
int s=0, w=1; ri char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') w=-1; ch=getchar(); }
while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch-'0'), ch=getchar();
return s*w;
}
void print(int x) { if(x<0) x=-x, putchar('-'); if(x>9) print(x/10); putchar(x%10+'0'); }
int n,m,a[N],root[N],tot,pp;
struct Node { int lc,rc,sum; }D[N*40];
#define mid (l+r>>1)
int Build(int l,int r)
{
int x=++tot;
if(l^r) D[x].lc=Build(l,mid), D[x].rc=Build(mid+1,r);
return x;
}
int UpDate(int pre,int l,int r,int pos)
{
int x=++tot;
D[x]=D[pre], D[x].sum=D[pre].sum+1;
if(l^r)
{
if(pos<=mid) D[x].lc=UpDate(D[pre].lc,l,mid,pos);
else D[x].rc=UpDate(D[pre].rc,mid+1,r,pos);
}
return x;
}
int Ask(int u,int v,int ql,int qr,int l,int r)
{
if(u>v) return 0;
if(l>=u&&r<=v) return D[qr].sum-D[ql].sum;
int res=0;
if(u<=mid) res+=Ask(u,v,D[ql].lc,D[qr].lc,l,mid);
if(v>mid) res+=Ask(u,v,D[ql].rc,D[qr].rc,mid+1,r);
return res;
}
signed main()
{
n=read(), m=read();
for(ri int i=1;i<=n;i++) a[i]=read(), pp=max(pp,a[i]);
root[0]=Build(0,pp);
for(ri int i=1;i<=n;i++) root[i]=UpDate(root[i-1],0,pp,a[i]);
for(ri int i=1;i<=m;i++)
{
int b,x,l,r,res=0;
b=read(), x=read(), l=read(), r=read();
for(ri int k=18;~k;k--)
{
int qwq=(b>>k)&1;
qwq^=1, qwq=(qwq<<k)+res;
if(Ask(max(qwq-x,0),min(pp,qwq+(1<<k)-1-x),root[l-1],root[r],0,pp)) res=qwq;
else res+=(((b>>k)&1)<<k);
}
printf("%d\n",res^b);
}
return 0;
}
夜畔流离回,暗叹永无殿。
独隐万花翠,空寂亦难迁。
千秋孰能为,明灭常久见。
但得心未碎,踏遍九重天。