首页 > 代码库 > FZU2105 Digits Count(经典 线段树)
FZU2105 Digits Count(经典 线段树)
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.
分析:逻辑运算都是按位运算的,所以一个数的不同位置进得按位运算都是互不影响的,而且每个数最多也就只有4位二进制位,所以可以看成四棵线段树,每个结点保存两个值:一个是当前区间内有多少个1,二是子结点是否需要进行XOR更新。
#include<stdio.h> struct node { int sum;//区间内1的个数,全1等价于当前区间数的第i位或运算,全0等价与运算(1&0=0,1&1=1,所以不用考虑位置与1相与) int XOR;//子节点是否需要异或 }tree[4][2*1000005]; int ans[1000005]; void builde(int l,int r,int k,int i) { int m=(l+r)/2; tree[i][k].XOR=0; if(l==r) { if((1<<i)&ans[l]) tree[i][k].sum=1; else tree[i][k].sum=0; return ; } builde(l,m,k*2,i); builde(m+1,r,k*2+1,i); tree[i][k].sum=tree[i][k*2].sum+tree[i][k*2+1].sum; } void set_childe(int l,int r,int k,int i) { int flag=0,m; m=(l+r)/2; if(tree[i][k].sum==r-l+1) { flag=1; tree[i][k*2].sum=m-l+1; tree[i][k*2+1].sum=r-m; } else if(tree[i][k].sum==0) tree[i][k*2].sum=tree[i][k*2+1].sum=0,flag=1; if(tree[i][k].XOR) { if(!flag)//还没有跟据父节点更新时 { tree[i][k*2].sum=(m-l+1)-tree[i][k*2].sum; tree[i][k*2+1].sum=(r-m)-tree[i][k*2+1].sum; } tree[i][k*2].XOR^=1; tree[i][k*2+1].XOR^=1; } tree[i][k].XOR=0; } void update_and(int l,int r,int k,int L,int R,int i) { int m=(l+r)/2; if(L<=l&&r<=R) { tree[i][k].sum=0; return ; } set_childe(l,r,k,i); if(L<=m) update_and(l,m,k*2,L,R,i); if(m<R) update_and(m+1,r,k*2+1,L,R,i); tree[i][k].sum=tree[i][k*2].sum+tree[i][k*2+1].sum; } void update_or(int l,int r,int k,int L,int R,int i) { int m=(l+r)/2; if(L<=l&&r<=R) { tree[i][k].sum=r-l+1; return ; } set_childe(l,r,k,i); if(L<=m) update_or(l,m,k*2,L,R,i); if(m<R) update_or(m+1,r,k*2+1,L,R,i); tree[i][k].sum=tree[i][k*2].sum+tree[i][k*2+1].sum; } void update_xor(int l,int r,int k,int L,int R,int i) { int m=(l+r)/2; if(L<=l&&r<=R) { tree[i][k].sum=(r-l+1)-tree[i][k].sum; tree[i][k].XOR^=1; return ; } set_childe(l,r,k,i); if(L<=m) update_xor(l,m,k*2,L,R,i); if(m<R) update_xor(m+1,r,k*2+1,L,R,i); tree[i][k].sum=tree[i][k*2].sum+tree[i][k*2+1].sum; } int query(int l,int r,int k,int L,int R,int i) { int m=(l+r)/2; if(L<=l&&r<=R) { return tree[i][k].sum; } set_childe(l,r,k,i); int sum=0; if(L<=m) sum+=query(l,m,k*2,L,R,i); if(m<R) sum+=query(m+1,r,k*2+1,L,R,i); return sum; } int main() { int t,n,m,L,R,opn; char str[10]; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&ans[i]); for(int i=0; i<4; i++) builde(1,n,1,i); while(m--) { scanf("%s",str); if(str[0]=='S') { scanf("%d%d",&L,&R); L++; R++; int sum=0,k; for(int i=0; i<4; i++) sum+=query(1,n,1,L,R,i)*(1<<i); printf("%d\n",sum); } else { scanf("%d%d%d",&opn,&L,&R); L++; R++; for(int i=0;i<4;i++) if(str[0]=='A') { if(!((1<<i)&opn)) update_and(1,n,1,L,R,i); } else if(str[0]=='O') { if((1<<i)&opn) update_or(1,n,1,L,R,i); } else if((1<<i)&opn) update_xor(1,n,1,L,R,i); } } } }
FZU2105 Digits Count(经典 线段树)