P3293 [SCOI2016]美味 最大异或值 主席树

  

可以先简化一下问题  看作是给你一个b  问再区间l r 内的数与之异或的最大值 

显然是从最高位到最低位开始贪心

主席树负责查询区间内是否有这个数

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);--i)
#define ll long long
#define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
#define inf 0x3f3f3f3f
#define CLR(A,v)  memset(A,v,sizeof A)
//////////////////////////////////
const int N=2e5+10;
int T[N],t[N<<5],lson[N<<5],rson[N<<5],ncnt;

void upnode(int x,int l,int r,int pre,int &pos)
{    
    pos=++ncnt;
    t[pos]=t[pre]+1;lson[pos]=lson[pre];rson[pos]=rson[pre];
    if(l==r)return ;int m=(l+r)>>1;
    if(x<=m)upnode(x,l,m,lson[pre],lson[pos]);
    else upnode(x,m+1,r,rson[pre],rson[pos]);
}
int qsum(int L,int R,int l,int r,int pre,int pos)
{    
    if(l>r||L>R)return 0;
    if(L<=l&&r<=R)return t[pos]-t[pre];
    int ans=0,m=l+r>>1;
    if(L<=m)ans+=qsum(L,R,l,m,lson[pre],lson[pos]);
    if(R>m)ans+=qsum(L,R,m+1,r,rson[pre],rson[pos]);
    return ans;
}
int a[N],n,m;
int main()
{
    scanf("%d%d",&n,&m);int maxx=0;
    rep(i,1,n)
    scanf("%d",&a[i]),maxx=max(maxx,a[i]);
    rep(i,1,n)
    upnode(a[i],0,maxx,T[i-1],T[i]);
    int b,x,l,r;
    while(m--)
    {
        int ans=0;
        scanf("%d%d%d%d",&b,&x,&l,&r);
        repp(i,23,0)
        {
            int c=(b>>i)&1;
            if(c&&!qsum(ans-x,ans-x+(1<<i)-1,0,maxx,T[l-1],T[r]))ans+=(1<<i);
            else if(!c&&qsum(ans-x+(1<<i),ans-x+(1<<i)+(1<<i)-1,0,maxx,T[l-1],T[r]))ans+=(1<<i);
        }
        printf("%d\n",ans^b);
    }
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/bxd123/p/11512502.html
今日推荐