您的位置:首页 > 其它

Coderforces 242E XOR on Segment

2013-03-10 13:14 330 查看
题意:给定一个序列,要求完成俩个操作

1)查询区间[l,r] 的和

2)区间更新, 区间每一个数都异或一个数x

对每一个查询输出结果

分析:对区间更新和查询这种操作,比较明显的就想到了线段树。区间查询比较简单,关键是区间更新该如何解决。

我们为线段数的每一个节点开一个cnt[20] 的数组,保存该区间内每一个数二进制位上1的个数,cnt[0] 表示对应区间内所有数第一个二进制数上1的个数和,这样,针对每一个异或操作,我们可以这样解决:

for(int i = 0; i < L; ++i)
{
if(!(v & ( 1 << i) )) continue;//针对异或操作的性质,如果v的第i位为0,则这个区间内,第i位上的1的个数不变;
                                //若第i位为1,则第i为上1 的个数和0 的个数互换
p[k].cnt[i] = p[k].r-p[k].l + 1 - p[k].cnt[i];
}


这样,在计算区间和时

for(int i = 0; i < L; ++i)
ans += ((p[k].cnt[i] * 1ll) << i);


当然,要加速对区间更新的操作,肯定要运用lazy的思想

完整代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<iostream>
#include<algorithm>

using namespace std;

const int N = 100000 + 10;
const int L = 20;

struct Node
{
int l,r;
int c,cnt[L];//cnt[i] 表示区间[l,r]内二进制第i位上1的个数
}p[3*N];
int que
;

void build(int k,int s,int t)
{
int kl, kr, mid;
p[k].l = s; p[k].r = t;p[k].c = 0;
if(s == t) {
for(int i = 0; i < L; ++i)
{
if(que[s] & ( 1 << i ))
p[k].cnt[i] = 1;
}
return ;
}
mid=(s + t) >> 1; kl = k << 1; kr = kl + 1;
build(kl, s, mid);
build(kr, mid+1, t);
for(int i = 0; i < L; ++i)
p[k].cnt[i] = p[kl].cnt[i] + p[kr].cnt[i];
}

void Push_Down(int k, int v)
{
p[k].c ^= v;
for(int i = 0; i < L; ++i)
{
if(!(v & ( 1 << i) )) continue;
p[k].cnt[i] = p[k].r-p[k].l + 1 - p[k].cnt[i];
}
}

void insert(int k,int s,int t,int v)
{
if(s <= p[k].l&& t >= p[k].r)
{
Push_Down(k, v);
return ;
}
else {

int mid=(p[k].r + p[k].l) >> 1, kl = k << 1, kr = kl + 1;
if(p[k].c != 0)
{
Push_Down(kl, p[k].c);
Push_Down(kr, p[k].c);
p[k].c = 0;
}
if(s <= mid) insert(kl, s, t, v);
if(t > mid) insert(kr, s, t, v);
for(int i = 0; i < L; ++i)
p[k].cnt[i] = p[kr].cnt[i] + p[kl].cnt[i];
}
}

__int64 query(int k,int s,int t)
{
if(s <= p[k].l && t >= p[k].r)
{
__int64 ans = 0;
for(int i = 0; i < L; ++i)
ans += ((p[k].cnt[i] * 1ll) << i);
return ans;
}

int mid=(p[k].r + p[k].l) >> 1,kl = k << 1,kr = kl + 1;

if(p[k].c)
{
Push_Down(kl, p[k].c);
Push_Down(kr, p[k].c);
p[k].c = 0;
}
__int64 a = 0,b = 0;
if(s <= mid) a = query(kl,s,t);
if(t > mid) b = query(kr,s,t);
for(int i = 0; i < L; ++i)
p[k].cnt[i] = p[kl].cnt[i] + p[kr].cnt[i];
return a + b;
}

int main()
{
int i,n,m,a,b,t,k;
scanf("%d",&n);
for(i = 1; i <= n; ++i) scanf("%d",que + i);
build(1,1,n);
scanf("%d",&m);
while(m--)
{
scanf("%d",&k);
if(k == 1)
{
scanf("%d %d",&a,&b);
printf("%I64d\n",query(1,a,b));
}
else
{
scanf("%d %d %d",&a,&b,&t);
if(t != 0)
insert(1,a,b,t);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: