标签:else for void can type cst || color 之间
题意:
给定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; }
标签:else for void can type cst || color 之间
原文地址:https://www.cnblogs.com/1124828077ccj/p/12247298.html