zoukankan      html  css  js  c++  java
  • dtoi3701 天照(amaterasu)

    题意:

         给定n个数字a[i],m个询问,每次询问给定l,r,x,求(a[l]+x)xor(a[l+1]+x)xor...xor(a[r]+x)。

    题解:

         分开来按位考虑。对于第i位,显然,大于第i位的数值都是没有意义的,可以全部丢掉看做0,无论是a还是x都可以这样处理。

         如果不+x,那么经过处理之后,第i位是1的值只可能在1000...~1111...之间,这是一个连续的区间,那么+x之后依然是一个连续区间(不过有可能会进位,所以要多考虑一种情况,反正都是连续区间),也就是说我们可以很容易得知,第i位是1的数字是在哪一段区间范围内。那么我们只需要求l,r中有多少个数字在这一段区间范围内即可。用可持久化线段树维护就能解决这道题了。

    #include<cstdio>
    #include<algorithm>
    #include<cstdlib>
    using namespace std;
    int n,m,tp,a[100002],rt[32][100002],cnt,sum[32],ans;
    typedef struct{
        int ls,rs;
        bool sum;
    }P;
    P p[30000002];
    void gengxin(int r1,int r2,int begin,int end,int wz){
        if (begin==end)
        {
            p[r2].sum=(p[r1].sum^1);return;
        }
        int mid=begin+(end-begin)/2;
        if (wz<=mid)
        {
            p[r2].ls=++cnt;p[r2].rs=p[r1].rs;
            gengxin(p[r1].ls,p[r2].ls,begin,mid,wz);
        }
        else
        {
            p[r2].rs=++cnt;p[r2].ls=p[r1].ls;
            gengxin(p[r1].rs,p[r2].rs,mid+1,end,wz);
        }
        p[r2].sum=(p[p[r2].ls].sum^p[p[r2].rs].sum);
    }
    bool chaxun(int r1,int r2,int begin,int end,int begin2,int end2){
        if (begin>end2 || end<begin2)return 0;
        if (begin>=begin2 && end<=end2)return (p[r2].sum^p[r1].sum);
        int mid=begin+(end-begin)/2;
        return (chaxun(p[r1].ls,p[r2].ls,begin,mid,begin2,end2)^chaxun(p[r1].rs,p[r2].rs,mid+1,end,begin2,end2));
    }
    int main()
    {
        sum[0]=1;
        for (int i=1;i<=30;i++)sum[i]=sum[i-1]+(1<<i);
        scanf("%d%d%d",&n,&m,&tp);
        for (int i=1;i<=n;i++)scanf("%d",&a[i]);
        for (int i=1;i<=n;i++)
        {
            for (int j=20;j>=0;j--)
            {
                rt[j][i]=++cnt;
                gengxin(rt[j][i-1],rt[j][i],0,sum[j+1],a[i]);
                if (a[i]&(1<<j))a[i]-=(1<<j);
            }
        }
        for (int i=1;i<=m;i++)
        {
            int l,r,x;
            scanf("%d%d%d",&l,&r,&x);
            l^=(tp*ans);r^=(tp*ans);x^=(tp*ans);
            ans=0;
            for (int j=20;j>=0;j--)
            {
                ans+=(chaxun(rt[j][l-1],rt[j][r],0,sum[j+1],max((1<<j)-x,0),sum[j]-x)^chaxun(rt[j][l-1],rt[j][r],0,sum[j+1],(1<<j+1)+(1<<j)-x,(1<<j+1)+sum[j]-x))*(1<<j);
                if (x&(1<<j))x-=(1<<j);
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    集合使用技巧
    集合总结
    Eclipse快捷键大全
    集合去掉重复元素的两种方式
    Collection集合的三种遍历方式
    win基本流程
    url
    StringBuffer7
    StringBuffer8
    StringBuffer6
  • 原文地址:https://www.cnblogs.com/1124828077ccj/p/12247298.html
Copyright © 2011-2022 走看看