链接:https://ac.nowcoder.com/acm/contest/283/J
来源:牛客网
RMQ
时间限制:C/C++ 3秒,其他语言6秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
空间限制: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开始
按位或在CC++、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的个数即可)。
“ | ”:由于它只要二进制上有1则为1,所以我们只需知道它二进制有无1即可。有则改为区间长度个数的1。
“ ^ ":由于它二进制上两者不同才为1,所以我们只需知道它二进制有无1即可。有则改为区间长度-之前存在1的个数的1。
//https://ac.nowcoder.com/acm/contest/283/J #include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=2e5+5; const int maxnbit=27; const string SUM="SUM"; const string OR="OR"; int n,m,val; struct Tree{ int lazy; int digit[maxnbit]; }tree[maxn<<2]; void up(int k){ for(int i=0;i<25;i++){///子树1个数相加等于父亲的1的个数 tree[k].digit[i]=tree[k<<1].digit[i]+tree[k<<1|1].digit[i]; } } void pushdown(int k,int l,int r){///下传 if(l==r) return ; tree[k<<1].lazy|=tree[k].lazy; tree[k<<1|1].lazy|=tree[k].lazy; ///tree[k<<1].lazy^=tree[k].lazy; ///tree[k<<1|1].lazy^=tree[k].lazy; int mid=(l+r)>>1; for(int i=0;i<25;i++){ if(tree[k].lazy&(1<<i)){ tree[k<<1].digit[i]=mid-l+1; tree[k<<1|1].digit[i]=r-mid; ///tree[k<<1].digit[i]=mid-l+1-digit[i]; ///tree[k<<1|1].digit[i]=r-mid-digit[i]; } } tree[k].lazy=0; } void build(int k,int l,int r){ tree[k].lazy=0; if(l==r){ scanf("%d",&val); for(int i=0;i<25;i++){ if(val&(1<<i)){ tree[k].digit[i]=1; }else{ tree[k].digit[i]=0; } } return ; } int mid=(l+r)>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); up(k); } void update(int k,int l,int r,int L,int R,int X){///[L,R]|X if(l>=L&&r<=R){ tree[k].lazy|=X; ///tree[k].lazy^=X; for(int i=0;i<25;i++){///更改第k个节点的第i位上1的个数 if(X&(1<<i)){ tree[k].digit[i]=r-l+1; } } return ; } if(tree[k].lazy) pushdown(k,l,r); int mid=(l+r)>>1; if(mid>=R) update(k<<1,l,mid,L,R,X); else if(mid<L) update(k<<1|1,mid+1,r,L,R,X); else{ update(k<<1,l,mid,L,R,X); update(k<<1|1,mid+1,r,L,R,X); } up(k); } ll ans; void query(int k,int l,int r,int L,int R){ if(l>=L&&r<=R){ for(int i=0;i<25;i++){///计算答案 ans+=1ll*tree[k].digit[i]*(1<<i); } return ; } if(tree[k].lazy) pushdown(k,l,r); int mid=(l+r)>>1; if(mid>=R) query(k<<1,l,mid,L,R); else if(mid<L) query(k<<1|1,mid+1,r,L,R); else{ query(k<<1,l,mid,L,R); query(k<<1|1,mid+1,r,L,R); } up(k); } int main(){ string q; int L,R,X; scanf("%d%d",&n,&m); build(1,1,n); while(m--){ cin>>q; if(q==SUM){ ans=0; scanf("%d%d",&L,&R); query(1,1,n,L,R); printf("%lld ",ans); }else if(q==OR){ scanf("%d%d%d",&L,&R,&X); update(1,1,n,L,R,X); } } return 0; }