(区间异或 / 区间或+求和)

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 %I64dspecifier.

Examples

input

Copy

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

Copy

26
22
0
34
11

input

Copy

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

Copy

38
28

解法一:将每个数拆分成 20 位二进制,意味着需要构建20棵线段树去维护每一位的变化;下推标记也要搞好,每次让其异或一个 1,而不是直接等于 1 ,因为两次相同异或,结果不改变。

(1400ms)

#include<set>
#include<map>
#include<list>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<bitset>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#define eps (1e-8)
#define MAX 0x3f3f3f3f
#define u_max 1844674407370955161
#define l_max 9223372036854775807
#define i_max 2147483647
#define re register
#define nth(k,n) nth_element(a,a+k,a+n);  // 将 第K大的放在k位
#define ko() for(int i=2;i<=n;i++) s=(s+k)%i // 约瑟夫
#define ok() v.erase(unique(v.begin(),v.end()),v.end()) // 排序,离散化
using namespace std;

inline int read(){
    char c = getchar(); int x = 0, f = 1;
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' & c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}

typedef long long ll;
const double pi = atan(1.)*4.;
const int M=1e3+5;
const int N=1e5+5;
int a[N];

struct fun{
    int tree[N<<2];
    int v[N<<2];
}f[25];                   //  20 棵线段树
 
void sett(int l,int r,int rt,int id){    //  建树
    if(l==r){
        f[id].tree[rt]=((1<<id)&a[l])?1:0;  
        return ;
    }
    int mid=l+r>>1;
    sett(l,mid,rt<<1,id);
    sett(mid+1,r,rt<<1|1,id);
    f[id].tree[rt]=f[id].tree[rt<<1]+f[id].tree[rt<<1|1];
}

void fun(int l,int r,int rt,int id){    //  标记下推
    if(f[id].v[rt]){
        f[id].v[rt<<1]^=f[id].v[rt];
        f[id].v[rt<<1|1]^=f[id].v[rt];
        int mid=l+r>>1;
        f[id].tree[rt<<1]=(mid-l+1)-f[id].tree[rt<<1];
        f[id].tree[rt<<1|1]=(r-mid)-f[id].tree[rt<<1|1];
        f[id].v[rt]=0;
    }
}

void upset(int x,int y,int l,int r,int rt,int id){
    if(x<=l&&y>=r){
        f[id].tree[rt]=(r-l+1)-f[id].tree[rt];
        f[id].v[rt]^=1;             //  要注意这块
        return ;
    }
    fun(l,r,rt,id);
    int mid=l+r>>1;
    if(x<=mid)
        upset(x,y,l,mid,rt<<1,id);
    if(y>mid)
        upset(x,y,mid+1,r,rt<<1|1,id);
    f[id].tree[rt]=f[id].tree[rt<<1]+f[id].tree[rt<<1|1];
}

int findd(int x,int y,int l,int r,int rt,int id){
    if(x<=l&&y>=r) return f[id].tree[rt];
    fun(l,r,rt,id);

    int mid=l+r>>1;
    int ans=0;
    if(x<=mid)
        ans+=findd(x,y,l,mid,rt<<1,id);
    if(y>mid)
        ans+=findd(x,y,mid+1,r,rt<<1|1,id);
    return ans;
}

int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) a[i]=read();

    for(int i=0;i<20;i++){
        memset(f[i].tree,0,sizeof(f[i].tree));
        memset(f[i].v,0,sizeof(f[i].v));
    }

    for(int i=0;i<20;i++)
        sett(1,n,1,i);

    int q,id,val,x,y;
    scanf("%d",&q);
    while(q--){
        scanf("%d",&id);
        if(id==1){
            scanf("%d %d",&x,&y);
            ll ans=0; ll d=1;
            for(int i=0;i<20;i++){
                ans+=d*findd(x,y,1,n,1,i);
             //   printf("d == %lld  find == %d\n",d,findd(x,y,1,n,1,i));
                d*=2;
            }
            printf("%I64d\n",ans);
        }
        else{
            scanf("%d %d %d",&x,&y,&val);
            for(int i=0;i<20;i++){
                if(((1<<i)&val))
                    upset(x,y,1,n,1,i);
            }
        }
    }
    return 0;
}

解法二:每个结点存放一个二进制,此时的下推标记为vel(需要异或的值)。

(450ms)

#include<set>
#include<map>
#include<list>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<bitset>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#define eps (1e-8)
#define MAX 0x3f3f3f3f
#define u_max 1844674407370955161
#define l_max 9223372036854775807
#define i_max 2147483647
#define re register
#define nth(k,n) nth_element(a,a+k,a+n);  // 将 第K大的放在k位
#define ko() for(int i=2;i<=n;i++) s=(s+k)%i // 约瑟夫
#define ok() v.erase(unique(v.begin(),v.end()),v.end()) // 排序,离散化
using namespace std;

inline int read(){
    char c = getchar(); int x = 0, f = 1;
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' & c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}

typedef long long ll;
const double pi = atan(1.)*4.;
const int M=1e3+5;
const int N=1e5+5;
int a[N];

struct fun{
    int w[20];    // 二进制结点
    int up;       // 下推标记
}tree[N<<2];

void push(int rt){
    for(int i=0;i<20;i++)
        tree[rt].w[i]=tree[rt<<1].w[i]+tree[rt<<1|1].w[i];
}

void sett(int l,int r,int rt){
    if(l==r){
        for(int i=0;i<20;i++)
            tree[rt].w[i]=((1<<i)&a[l])?1:0;
        return ;
    }
    int mid=l+r>>1;
    sett(l,mid,rt<<1);
    sett(mid+1,r,rt<<1|1);
    push(rt);
}

void get(int l,int r,int rt,int vel){
    for(int i=0;i<20;i++){
        if(vel&(1<<i)){       //  下推标记的第 i 为 1 ,更新
            tree[rt].w[i]=(r-l+1)-tree[rt].w[i];
        }
    }
}

void fun(int l,int r,int rt){
    if(tree[rt].up){
        tree[rt<<1].up^=tree[rt].up;      // 标记下放
        tree[rt<<1|1].up^=tree[rt].up;
        int mid=l+r>>1;
        get(l,mid,rt<<1,tree[rt].up);
        get(mid+1,r,rt<<1|1,tree[rt].up);
        tree[rt].up=0;
    }
}

void upset(int x,int y,int vel,int l,int r,int rt){
    if(x<=l&&y>=r){
        get(l,r,rt,vel);
        tree[rt].up^=vel;
        return ;
    }
    fun(l,r,rt);
    int mid=l+r>>1;
    if(x<=mid) upset(x,y,vel,l,mid,rt<<1);
    if(y>mid) upset(x,y,vel,mid+1,r,rt<<1|1);
    push(rt);
}
ll ans=0;
void findd(int x,int y,int l,int r,int rt){
    if(x<=l&&y>=r){
        ll d=1;
        for(int i=0;i<20;i++){
            ans+=d*tree[rt].w[i];
            d*=2;
        }
        return ;
    }
    fun(l,r,rt);
    int mid=l+r>>1;
    if(x<=mid) findd(x,y,l,mid,rt<<1);
    if(y>mid) findd(x,y,mid+1,r,rt<<1|1);
}

int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) a[i]=read();
    sett(1,n,1);
    int q,id,vel,x,y;
    scanf("%d",&q);
    while(q--){
        scanf("%d",&id);
        if(id==1){
            scanf("%d %d",&x,&y);
            ans=0;
            findd(x,y,1,n,1);
            printf("%I64d\n",ans);
        }
        else{
            scanf("%d %d %d",&x,&y,&vel);
            upset(x,y,vel,1,n,1);
        }
    }
    return 0;
}

链接:https://ac.nowcoder.com/acm/contest/283/J
来源:牛客网

时间限制:C/C++ 3秒,其他语言6秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld

题目描述

按位或运算:处理两个长度相同的二进制数,两个相应的二进位中只要有一个为1,该位的结果值为1。例如5 or 3 = 7

        0101(十进制5)
     OR 0011(十进制3)
      = 0111(十进制7)
—— 引用自 位运算——维基百科

小姐姐想要一种数据结构,支持如下操作:

对于一个整数数组:    

1. 给定L和R,输出[L,R]中元素的和

2. 给定L,R和X,将[L,R]中每个元素与X进行按位或运算

3. 数组索引从1开始

按位或在C\C++、Java、Python中为'|'运算符

输入描述:

第一行为两个整数 n 和 m,表示数组元素个数和操作的次数

第二行有n个整数,第i个表示数组array中第i个元素的值array[i]

接下来m行,每行只有两种可能:

1. SUM L R

表示对[L,R]的元素求和并输出

2. OR L R X

表示对[L,R]的每一个元素与X进行按位或运算,L、R为base 1的数字序号

数据满足:

1≤n,m≤2000001≤n,m≤200000

1≤arrayi,X≤10000001≤arrayi,X≤1000000

1≤L,R≤n1≤L,R≤n

输出描述:

对于每个SUM操作,在一行内输出该操作的结果。

示例1

输入

复制

5 3
1 2 3 4 5
SUM 1 4
OR 2 5 10
SUM 1 4

输出

复制

10
36

说明

在第一个SUM操作时数组a为[1, 2, 3, 4, 5],因此[1,4]和为10

在第二个SUM操作时数组a为[1, 10, 11, 14, 15],因此[1,4]和为36
#include<set>
#include<map>
#include<list>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<bitset>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#define eps (1e-8)
#define MAX 0x3f3f3f3f
#define u_max 1844674407370955161
#define l_max 9223372036854775807
#define i_max 2147483647
#define re register
#define nth(k,n) nth_element(a,a+k,a+n);  // 将 第K大的放在k位
#define ko() for(int i=2;i<=n;i++) s=(s+k)%i // 约瑟夫
#define ok() v.erase(unique(v.begin(),v.end()),v.end()) // 排序,离散化
using namespace std;

inline int read(){
    char c = getchar(); int x = 0, f = 1;
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' & c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}

typedef long long ll;
const double pi = atan(1.)*4.;
const int M=1e3+5;
const int N=2e5+5;
int a[N];

struct fun{
    int w[20];
    int up;
}tree[N<<2];

void push(int rt){
    for(int i=0;i<20;i++)
        tree[rt].w[i]=tree[rt<<1].w[i]+tree[rt<<1|1].w[i];
}

void sett(int l,int r,int rt){
    if(l==r){
        for(int i=0;i<20;i++)
            tree[rt].w[i]=((1<<i)&a[l])?1:0;
        return ;
    }
    int mid=l+r>>1;
    sett(l,mid,rt<<1);
    sett(mid+1,r,rt<<1|1);
    push(rt);
}

void get(int l,int r,int rt,int vel){
    for(int i=0;i<20;i++){
        if(vel&(1<<i)){
            tree[rt].w[i]=r-l+1;
        }
    }
}

void fun(int l,int r,int rt){
    if(tree[rt].up){
        tree[rt<<1].up|=tree[rt].up;
        tree[rt<<1|1].up|=tree[rt].up;
        int mid=l+r>>1;
        get(l,mid,rt<<1,tree[rt].up);
        get(mid+1,r,rt<<1|1,tree[rt].up);
        tree[rt].up=0;
    }
}

void upset(int x,int y,int vel,int l,int r,int rt){
    if(x<=l&&y>=r){
        get(l,r,rt,vel);
        tree[rt].up|=vel;
        return ;
    }
    fun(l,r,rt);
    int mid=l+r>>1;
    if(x<=mid) upset(x,y,vel,l,mid,rt<<1);
    if(y>mid) upset(x,y,vel,mid+1,r,rt<<1|1);
    push(rt);
}
ll ans=0;
void findd(int x,int y,int l,int r,int rt){
    if(x<=l&&y>=r){
        ll d=1;
        for(int i=0;i<20;i++){
            ans+=d*tree[rt].w[i];
            d*=2;
        }
        return ;
    }
    fun(l,r,rt);
    int mid=l+r>>1;
    if(x<=mid) findd(x,y,l,mid,rt<<1);
    if(y>mid) findd(x,y,mid+1,r,rt<<1|1);
}

char s[10];
int main(){
    int n,m,x,y,vel;
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++) a[i]=read();
    sett(1,n,1);
    while(m--){
        scanf(" %s",s);
        if(s[0]=='S'){
            scanf("%d %d",&x,&y);
            ans=0;
            findd(x,y,1,n,1);
            printf("%lld\n",ans);
        }
        else{
            scanf("%d %d %d",&x,&y,&vel);
            upset(x,y,vel,1,n,1);
        }
    }
    return 0;
}

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值