dtoi3701 天照(amaterasu)

时间:2020-02-01 00:44:38   收藏:0   阅读:63

题意:

     给定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\n",ans);
    }
    return 0;
}
评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!