题目链接:https://vjudge.net/problem/Gym-100739A
Queries
XORin discovers an interesting function called Elf. XORina has given XORin an array A of N integers and Q queries. The queries are of 2 types:
1 p x - the element on the position p changes his value to x (Ap=x)
2 a b - find the sum of Elf(i,j) for each a ≤ i ≤ j ≤ b, where Elf(i,j)=Ai xor Ai + 1 xor ... xor Aj.
Your task is to print the responses to the 2nd type of queries.
Input
The first line of the input contains n, the size of the array. The second line of the input contains m, the number of queries (1 ≤ n, m ≤ 100000). The third line of the input contains n numbers, the initial elements of the array (each of them is between 1 and 1000). On the next m lines each line contains a query. The first type of query is 1 p x (1 ≤ p ≤ n and 0 ≤ x ≤ 1000). The second type of query is 2 a b (1 ≤ a ≤ b ≤ n).
Output
The output contains the answer to the second type of queries, each answer on a line. Print the answer modulo 4001.
Examples
Input
4 8 1 2 3 4 2 1 2 1 1 2 2 1 3 2 1 4 1 3 7 2 1 3 1 4 5 2 1 4
Output
6 11 34 23 32
题目大意:给你一个数组,对数组进行单点修改,查询区间内所有子区间的异或和。
思路:利用线段树容易想到,重要的是进行拆位维护,对于每个二进制位开一个线段树
合并:维护区间从左端开始、从右端点开始、从或不从左右端点开始(全部)的异或和为0、1的区间个数,然后进行合并
具体详见代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<string>
using namespace std;
typedef long long ll;
const int MOD=4001;
int n,m;
const int INF=1e5+5;
int a[INF];
struct node{
int d;//区间的异或值
int l,r;//区间的左右边界
int le[2],re[2];//以左或右端点为起点的区间异或值为1或0的个数
int sum[2];//区间异或值为1或0的个数
}f[10][INF*3];//2*INF会导致内存不够,4*INF会导致内存溢出,3*INF刚好AC
int bit[12],b[INF][10];//每个数的二进制位
int bb[10];
void init()
{
int i,j,cnt;
bit[0]=1;
for(i=1;i<=10;i++)
{
bit[i]=bit[i-1]*2;
}
for(i=1;i<=n;i++)
{
j=a[i];
cnt=0;
while(j){
b[i][cnt++]=j%2;
j=j/2;
}
}
}
//区间合并
node push_up(int id,int ans,node u,node v)//返回node,利于查询时的区间合并
{
node w;
if(ans){
w=f[id][ans];
}
w.d =u.d^v.d ;//区间的值等于其左右子区间的值的异或
//若左子区间为1,则加上v.le[1],,因为1^1=0,下面都同理
w.le[0]=(u.le[0]+v.le[u.d==0?0:1])%MOD;
w.le[1]=(u.le[1]+v.le[u.d==0?1:0])%MOD;
w.re[0]=(v.re[0]+u.re[v.d==0?0:1])%MOD;
w.re[1]=(v.re[1]+u.re[v.d==0?1:0])%MOD;
//同理0^0=0,1^1=0;进行区间合并
w.sum[0]=(u.sum[0]+v.sum[0]+u.re[0]*v.le[0]+u.re[1]*v.le[1])%MOD;
w.sum[1]=(u.sum[1]+v.sum[1]+u.re[0]*v.le[1]+u.re[1]*v.le[0])%MOD;
return w;
}
void build(int id,int ans,int l,int r)//建树
{
f[id][ans].l =l;f[id][ans].r =r;
if(l==r){
int dd=b[l][id];
f[id][ans].d =dd;
f[id][ans].le[dd]=f[id][ans].re[dd]=f[id][ans].sum[dd]=1;
f[id][ans].le[dd^1]=f[id][ans].re[dd^1]=f[id][ans].sum[dd^1]=0;
return ;
}
int mid=(l+r)>>1;
build(id,ans<<1,l,mid);
build(id,ans<<1|1,mid+1,r);
f[id][ans]=push_up(id,ans,f[id][ans<<1],f[id][ans<<1|1]);
}
void change(int id,int ans,int l)//区间修改
{
if(f[id][ans].l ==f[id][ans].r &&f[id][ans].l ==l){
int u=bb[id];
f[id][ans].d =u;
f[id][ans].le[u]=f[id][ans].re[u]=f[id][ans].sum[u]=1;
f[id][ans].le[u^1]=f[id][ans].re[u^1]=f[id][ans].sum[u^1]=0;
return ;
}
int mid=(f[id][ans].l+f[id][ans].r )>>1;
if(l<=mid)
{
change(id,ans<<1,l);
}
else change(id,ans<<1|1,l);
f[id][ans]=push_up(id,ans,f[id][ans<<1],f[id][ans<<1|1]);
}
node query(int id,int ans,int l,int r)//区间查询
{
if(f[id][ans].l ==l&&f[id][ans].r ==r){
return f[id][ans];
}
int mid=(f[id][ans].l +f[id][ans].r )>>1;
if(r<=mid){
return query(id,ans<<1,l,r);
}
else if(l>mid){
return query(id,ans<<1|1,l,r);
}
else{
node u,v;
u=query(id,ans<<1,l,mid);
v=query(id,ans<<1|1,mid+1,r);
return push_up(0,0,u,v);
}
}
int main()
{
cin>>n>>m;
int i,j,k;
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
init();
for(i=0;i<10;i++)
{
build(i,1,1,n);
}
int ans;
while(m--)
{
scanf("%d%d%d",&i,&j,&k);
if(i==1)
{
int u=k,v=0;
while(u)
{
bb[v++]=u%2;
u=u/2;
}
for(i=0;i<v;i++)
{
if(b[j][i]!=bb[i]) //进行剪枝 ,降低时间复杂度
change(i,1,j);
b[j][i]=bb[i];
}
for(i=v;i<10;i++)//注意这,要全部更新
{
bb[i]=0;
if(b[j][i]!=bb[i]) //剪枝
change(i,1,j);
b[j][i]=bb[i];
}
}
else if(i==2)
{
ans=0;
node u;
for(i=0;i<10;i++)
{
u=query(i,1,j,k);
ans=(ans+u.sum[1]*bit[i])%MOD;
}
printf("%d\n",ans);
}
}
return 0;
}
也可以利用l0+l1的关系,维护更少的内容,
点击链接:https://blog.csdn.net/alan_cty/article/details/50804865