loj #2016. 「SCOI2016」美味

版权声明:本文为博主原创文章,爱转载的表明出处就好. https://blog.csdn.net/qq_36797743/article/details/81736649

题意

链接

题解

想了一会。。
这种异或的题,一般考虑一位一位确定
考虑,如果我们确定了一个前缀,那么能选的数一定是一个区间
当我们确定下一位的时候,看一下新的区间是否有树可以符合就行了
是否符合用主席树解决
时间复杂度是 O ( n l o g 2 n )
CODE:

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
const int N=200005;
const int M=200005*22;
int S=(1<<20);
int n,m;
int s1[M],s2[M],c[M],num=0;
int rt[N];
void change (int &now,int l,int r,int x)
{
    if (now==0) now=++num;
    c[now]++;
    if (l==r) return ;
    int mid=(l+r)>>1;
    if (x<=mid) change(s1[now],l,mid,x);
    else change(s2[now],mid+1,r,x);
}
void Merge (int &rt,int rt1)
{
    if (rt==0)  {rt=rt1;return ;}
    if (rt1==0) return ;
    c[rt]+=c[rt1];
    Merge(s1[rt],s1[rt1]);
    Merge(s2[rt],s2[rt1]);
}
int calc (int now,int l,int r,int L,int R)
{
    if (L>R) return 0;
    L=max(L,0);R=max(R,0);
    if (now==0) return 0;
    if (l==L&&r==R) return c[now];
    int mid=(l+r)>>1;
    if (R<=mid) return calc(s1[now],l,mid,L,R);
    else if (L>mid) return calc(s2[now],mid+1,r,L,R);
    else return calc(s1[now],l,mid,L,mid)+calc(s2[now],mid+1,r,mid+1,R);
}
int main()
{
    freopen("food1.in","r",stdin);
    freopen("a.out","w",stdout);
    scanf("%d%d",&n,&m);
    for (int u=1;u<=n;u++)
    {
        int x;
        scanf("%d",&x);
        change(rt[u],0,S,x);
        Merge(rt[u],rt[u-1]);
    //  if (num>=N*21)printf("%d %d\n",u,num);
    }
    for (int u=1;u<=m;u++)
    {
        int a,b,l,r;
        scanf("%d%d%d%d",&a,&b,&l,&r);
        //a xor  (b+x[i])
        int L=0,R=0;//在已经控制了的位中,答案区间是这一段都是合法的 
        int ans=0;
        for (int u=18;u>=0;u--)
        {
            int x=(1<<u),xx=x-1;
            if ((a&x)!=0)//这一位是1,那么我们需要一个0
            {
                //printf("%d %d\n",L-b,R+xx-b);
                //printf("YES:%d %d %d\n",u,calc(rt[r],0,S,L-b,R+xx-b),calc(rt[l-1],0,S,L-b,R+xx-b));
                if (calc(rt[r],0,S,L-b,R+xx-b)-calc(rt[l-1],0,S,L-b,R+xx-b)>0)  ans=ans+x;
                else    {R=R+x;L=L+x;}
            }
            else//我们这一位需要一个1 
            {
            //  printf("%d %d\n",L-b+x,R+xx-b+x);
            //  printf("OZY:%d %d %d\n",u,calc(rt[r],0,S,L+x-b,R+x+xx-b),calc(rt[l-1],0,S,L+x-b,R+x+xx-b));
                if (calc(rt[r],0,S,L+x-b,R+x+xx-b)-calc(rt[l-1],0,S,L+x-b,R+x+xx-b)>0) 
                {
                    L+=x;
                    R+=x;
                    ans=ans+x;
                }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_36797743/article/details/81736649