Codeforce-242E-XOR on Segment(线段树区间更新)

E. XOR on Segment
time limit per test:4 seconds
memory limit per test:256 megabytes
input:standard input
output:standard output

You've got an array a, consisting of n integers a1, a2, ..., an. You are allowed to perform two operations on this array:

  1. Calculate the sum of current array elements on the segment [l, r], that is, count value al + al + 1 + ... + ar.
  2. Apply the xor operation with a given number x to each array element on the segment [l, r], that is, execute . This operation changes exactly r - l + 1 array elements.

Expression means applying bitwise xor operation to numbers x and y. The given operation exists in all modern programming languages, for example in language C++ and Java it is marked as "^", in Pascal — as "xor".

You've got a list of m operations of the indicated type. Your task is to perform all given operations, for each sum query you should print the result you get.

Input

The first line contains integer n (1 ≤ n ≤ 105) — the size of the array. The second line contains space-separated integers a1, a2, ..., an (0 ≤ ai ≤ 106) — the original array.

The third line contains integer m (1 ≤ m ≤ 5·104) — the number of operations with the array. The i-th of the following m lines first contains an integer ti (1 ≤ ti ≤ 2) — the type of the i-th query. If ti = 1, then this is the query of the sum, if ti = 2, then this is the query to change array elements. If the i-th operation is of type 1, then next follow two integers li, ri (1 ≤ li ≤ ri ≤ n). If the i-th operation is of type 2, then next follow three integers li, ri, xi (1 ≤ li ≤ ri ≤ n, 1 ≤ xi ≤ 106). The numbers on the lines are separated by single spaces.

Output

For each query of type 1 print in a single line the sum of numbers on the given segment. Print the answers to the queries in the order in which the queries go in the input.

Please, do not use the %lld specifier to read or write 64-bit integers in С++. It is preferred to use the cin, cout streams, or the %I64d specifier.

Examples
Input
5
4 10 3 13 7
8
1 2 4
2 1 3 3
1 2 4
1 3 3
2 2 5 5
1 1 5
2 1 2 10
1 2 3
Output
26
22
0
34
11
Input
6
4 7 4 0 7 3
5
2 2 3 8
1 1 5
2 3 5 1
2 4 5 6
1 2 3
Output
38
28

题意:给出n个点,m次操作,1 x y:查询区间x-y的和,2 l r x,区间l-r每个数^x;

思路:线段树区间更新,每个节点维护当前区间每一位(32位)1的个数,要更改时就区间更新一下,容易想到区间每个数^一个数的话,如果改数第i位为1,则tag[i]=区间长度-tag[i];然后写一写就ok了

AC代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define maxn 100005
using namespace std;
int arr[maxn],n,m,tmp[33],base[33];
void getbase()
{
    base[0]=1;
    for(int i=1;i<=31;i++)
        base[i]=2*base[i-1];
}
struct node
{
    int l,r;
    int tag[33];//存二进制第几位有几个1
    int lazy[33];//lazy[i]为奇数则需要改变,为偶数则相当于第i位^的值抵消
}tree[maxn*4];
void pushup(int root)
{
    for(int i=0;i<32;i++)
        tree[root].tag[i]=tree[root<<1].tag[i]+tree[root<<1|1].tag[i];
}
void build(int root,int l,int r)
{
    tree[root].l=l;
    tree[root].r=r;
    memset(tree[root].lazy,0,sizeof(tree[root].lazy));
    if(l==r)
    {
        for(int i=0;i<32;i++)
        {
            if(arr[l]&(1<<i))
                tree[root].tag[i]++;
        }
        return;
    }
    int mid=(l+r)>>1;
    build(root<<1,l,mid);
    build(root<<1|1,mid+1,r);
    pushup(root);
}
void pushdown(int root)
{
    for(int i=0;i<32;i++)
    {
        if(tree[root].lazy[i]%2)
        {
            tree[root<<1].lazy[i]++;
            tree[root<<1|1].lazy[i]++;
            tree[root<<1].tag[i]=tree[root<<1].r-tree[root<<1].l+1-tree[root<<1].tag[i];
            tree[root<<1|1].tag[i]=tree[root<<1|1].r-tree[root<<1|1].l+1-tree[root<<1|1].tag[i];
            tree[root].lazy[i]++;
        }
    }
}
void update(int root,int l,int r,int v)
{
    int ll=tree[root].l;
    int rr=tree[root].r;
    if(l<=ll&&rr<=r)
    {
        for(int i=0;i<32;i++)
        {
            if(v&(1<<i))
            {
                int cnt=rr-ll+1;
                tree[root].tag[i]=cnt-tree[root].tag[i];
                tree[root].lazy[i]++;
            }
        }
        return;
    }
    pushdown(root);
    int mid=(ll+rr)>>1;
    if(l<=mid) update(root<<1,l,r,v);
    if(r>mid) update(root<<1|1,l,r,v);
    pushup(root);
}
long long query(int root,int l,int r)
{
    int ll=tree[root].l;
    int rr=tree[root].r;
    if(l<=ll&&rr<=r)
    {
        long long sum=0;
        for(int i=0;i<32;i++)
            sum+=(long long)tree[root].tag[i]*base[i];
        return sum;
    }
    pushdown(root);
    long long ans=0;
    int mid=(ll+rr)>>1;
    if(l<=mid)
        ans+=query(root<<1,l,r);
    if(r>mid)
        ans+=query(root<<1|1,l,r);
    pushup(root);
    return ans;
}
int main()
{
    getbase();
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&arr[i]);
    build(1,1,n);
    scanf("%d",&m);
    int op,x,y,z;
    while(m--)
    {
        scanf("%d%d%d",&op,&x,&y);
        if(op==1)
            printf("%I64d\n",query(1,x,y));
        else
        {
            scanf("%d",&z);
            update(1,x,y,z);
        }
    }
    return 0;
}


发布了76 篇原创文章 · 获赞 9 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_37171272/article/details/78255455