[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;
}
posted @ 2020-08-07 08:02  zkdxl  阅读(66)  评论(0编辑  收藏  举报