FZU-2105 Digits Count(线段树)
来源:互联网 发布:淘宝帐号俩个手机登陆 编辑:程序博客网 时间:2024/05/23 00:41
Accept: 441 Submit: 2070
Time Limit: 10000 mSec Memory Limit : 262144 KB
Problem Description
Given N integers A={A[0],A[1],...,A[N-1]}. Here we have some operations:
Operation 1: AND opn L R
Here opn, L and R are integers.
For L≤i≤R, we do A[i]=A[i] AND opn (here "AND" is bitwise operation).
Operation 2: OR opn L R
Here opn, L and R are integers.
For L≤i≤R, we do A[i]=A[i] OR opn (here "OR" is bitwise operation).
Operation 3: XOR opn L R
Here opn, L and R are integers.
For L≤i≤R, we do A[i]=A[i] XOR opn (here "XOR" is bitwise operation).
Operation 4: SUM L R
We want to know the result of A[L]+A[L+1]+...+A[R].
Now can you solve this easy problem?
Input
The first line of the input contains an integer T, indicating the number of test cases. (T≤100)
Then T cases, for any case, the first line has two integers n and m (1≤n≤1,000,000, 1≤m≤100,000), indicating the number of elements in A and the number of operations.
Then one line follows n integers A[0], A[1], ..., A[n-1] (0≤A[i]<16,0≤i<n).
Then m lines, each line must be one of the 4 operations above. (0≤opn≤15)
Output
Sample Input
Sample Output
Hint
A = [1 2 4 7]
SUM 0 2, result=1+2+4=7;
XOR 5 0 0, A=[4 2 4 7];
OR 6 0 3, A=[6 6 6 7];
SUM 0 2, result=6+6+6=18.
Source
“高教社杯”第三届福建省大学生程序设计竞赛
题意:给出有n个数(0<A[i]<16)的序列,一共有4种操作:①AND opn L R,将区间[L,R]内的数与opn进行与运算;②OR opn L R,将区间[L,R]内的数与opn进行或运算
③XOR opn L R,将区间[L,R]内的数与opn进行异或运算;④SUM L R,输出区间[L,R]内的数之和.(0<=opn<=15)
题解:位运算的线段树,我们发现A[i]和opn都是小于16的,就说明它们的二进制位数不超过4,那么我们可以将这些数的每一位用线段树保存,然后在每一位上进行位运算,
这样就可以起到线段树的维护效果.下面对于每种运算进行分析:①与运算:1&1=1,1&0=0,0&0=0,从这3个式子可以看出,进行与运算的时候,如果opn的某一位是0,那么A[i]
相应的那一位就一定要变成0,然而opn的某一位是1,进行与运算之后A[i]的相应为还是不会改变的;②或运算:1|1=1,1|0=1,0|0=0,其实或运算和与运算就是完全相反的,
如果opn的某一位是1,那么A[i]相应的哪一位就一定要变成1,然而opn的某一位是0,进行与运算之后A[i]的相应为还是不会改变的;③异或运算:1^1=0,1^0=1,0^0=0,其实这
道题最难的就是异或运算,前两种运算都是直接覆盖这段区间就可以了,然而异或运算时反转,这样的话就需要再加一个懒惰标记X,跟或运算相同的是,只有当某一位是1的时候
才要进行异或运算,如果这一位被标记了覆盖的懒惰标记(cover[rt]!=-1),那么就将他反转(oover[rt]^=1),因为如果这一位是要覆盖为1的,反转之后自然就是覆盖为0,如果
没有标记覆盖的懒惰标记,则将反转的懒惰标记进行反转(X[rt]^=1);
#include<cstdio>#include<algorithm>#include<string.h>#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1using namespace std;typedef long long LL;const int maxn = 1e6 + 5;int sum[4][maxn<<2];int cover[4][maxn<<2],X[4][maxn<<2];void PushUP(int rt){ for(int i=0;i<4;i++) sum[i][rt]=sum[i][rt<<1]+sum[i][rt<<1|1];}void build(int l,int r,int rt){ for(int i=0;i<4;i++){ cover[i][rt]=-1;//覆盖标记初始化 X[i][rt]=0;//反转标记初始化 sum[i][rt]=0;//总和初始化 } if(l==r){ int x; scanf("%d",&x); for(int i=0;i<4;i++) if(x&(1<<i)) sum[i][rt]=1;//将序列中每个数的每一位存入线段树 return; } int m=(l+r)>>1; build(lson); build(rson); PushUP(rt);}void FXOR(int i,int rt){//进行反转操作 if(cover[i][rt]!=-1) cover[i][rt]^=1; else X[i][rt]^=1;}void PushDown(int rt,int m){//将懒惰标记下移 for(int i=0;i<4;i++) { if(cover[i][rt]!=-1){//如果有覆盖标记就把覆盖标记下移 sum[i][rt<<1]=(m-(m>>1))*cover[i][rt]; sum[i][rt<<1|1]=(m>>1)*cover[i][rt]; cover[i][rt<<1]=cover[i][rt<<1|1]=cover[i][rt]; X[i][rt<<1]=X[i][rt<<1|1]=0; cover[i][rt]=-1; } if(X[i][rt]){//如果有反转标记就把反转标记下移 sum[i][rt<<1]=m-(m>>1)-sum[i][rt<<1]; sum[i][rt<<1|1]=(m>>1)-sum[i][rt<<1|1]; FXOR(i,rt<<1); FXOR(i,rt<<1|1); X[i][rt]=0; } }}void update(char op,int L,int R,int c,int l,int r,int rt){ if(L<=l&&R>=r){ for(int i=0;i<4;i++){ if(c&(1<<i)){//当第i位是1的时候进行或/异或运算 int len=r-l+1; if(op=='O'){ sum[i][rt]=len; cover[i][rt]=1; X[i][rt]=0; } else if(op=='X'){ sum[i][rt]=len-sum[i][rt]; FXOR(i,rt); } } else if(op=='A'){//当第i位是0的时候进行与运算 sum[i][rt]=0; cover[i][rt]=0; X[i][rt]=0; } } return; } PushDown(rt,r-l+1); int m=(l+r)>>1; if(L<=m) update(op,L,R,c,lson); if(R>m) update(op,L,R,c,rson); PushUP(rt);}int query(int L,int R,int l,int r,int rt){ if(L<=l&&R>=r){ int ans=0; for(int i=0;i<4;i++) ans+=sum[i][rt]*(1<<i);//总和=第i位1的个数*2^i return ans; } PushDown(rt,r-l+1); int m=(l+r)>>1; int ret=0; if(L<=m) ret+=query(L,R,lson); if(R>m) ret+=query(L,R,rson); PushUP(rt); return ret;}int main(){ int T; // freopen("input.txt","r",stdin); scanf("%d",&T); while(T--){ int n,m; scanf("%d%d",&n,&m); build(0,n-1,1); int a,b,c; char op[15]; while(m--){ scanf("%s",op); if(op[0]=='S'){ scanf("%d%d",&a,&b); printf("%d\n",query(a,b,0,n-1,1)); } else { scanf("%d%d%d",&c,&a,&b); update(op[0],a,b,c,0,n-1,1); } } } return 0;}
- fzu 2105 Digits Count 线段树
- 【线段树】 FZU 2105 Digits Count
- 【FZU】2105 Digits Count 线段树
- 【线段树】 FZU 2105 Digits Count
- FZU 2105 Digits Count(线段树)
- FZU-2105 Digits Count(线段树)
- FZU 2105 Digits Count(线段树区间修改)
- fzu 2105 Digits Count (线段树区间更新)
- [FZU 2105 Digits Count] 线段树区间的复合操作
- fzu 2105 Digits Count
- FZU 2105 Digits Count
- FZU 2105 Digits Count
- FZU 2105 Digits Count
- FZU 2105 Digits Count
- fzu 2105——Digits Count
- FZU 2105 Digits Count 区间更新
- [FOJ 2105][Vjudge 35179] Digits Count [线段树]
- FZU2105-Digits Count(线段树区间)
- kaggle项目实战一
- 一元购宝倒计时之angularJs-$interval
- onActivityResult:拍照不进入原因
- iOS崩溃堆栈信息的符号化解析
- Map 集合详解HashMap_TreeMap_LinkedHashMap
- FZU-2105 Digits Count(线段树)
- RxJava学习(十二)
- 安卓谷歌电子市场学习笔记系列——怎么移除集合中的元素(迭代器的使用)
- Centos 7.0 通过rsync和inotify实现实时同步
- 线程池ThreadPoolExecutor使用简介
- 2016.8.24--字符串匹配
- JavaScript红宝书笔记:(第四章)变量、作用域、内存
- 线上机器没有开coredump情况下的查错
- Unity3D 基于UGUI的图文混排组件