fzu 2105 Digits Count ( 线段树 ) from 第三届福建省大学生程序设计竞赛
http://acm.fzu.edu.cn/problem.php?pid=2105
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
“高教社杯”第三届福建省大学生程序设计竞赛
【题解】:
这题思路想到 经过多次操作之后的区间应该是一个数字很多相同的区间:
因为如果相邻两个数经过操作之后变成相同的数了,那么再经过覆盖了该区间的操作时,那么他们的值将同时发生改变,变成另外一个相同的值,这多次操作下去,之后将生更多的相同的数字区间,这里的相同数字就是懒惰标记更新的关键:例如:OR 6 0 3, A=[6 6 6 7]; 其中6出现了3次
详见代码:
【code】:
1 /** 2 status:Accepted language:Visual C++ 3 time:1953 ms memory:47156KB 4 code length:2686B author:cj 5 */ 6 #include <iostream> 7 #include <cstdio> 8 #include <cstring> 9 #define N 1000010 10 #define lson p<<1 11 #define rson p<<1|1 12 using namespace std; 13 14 struct Nod 15 { 16 int l,r; 17 int num; //标记区间数字是否相同 18 }node[N<<2]; 19 20 void building(int l,int r,int p) 21 { 22 node[p].l = l; 23 node[p].r = r; 24 node[p].num = -1; 25 if(l==r) 26 { 27 scanf("%d",&node[p].num); 28 return; 29 } 30 int mid = (l+r)>>1; 31 building(l,mid,lson); 32 building(mid+1,r,rson); 33 if(node[lson].num!=-1&&node[lson].num==node[rson].num) //向上更新 34 { 35 node[p].num = node[lson].num; 36 } 37 } 38 39 int opreate(int op,int opn,int num) //操作函数 op:操作符 opn,num:操作数 40 { 41 if(op==1) return opn# 42 if(op==2) return opn|num; 43 if(op==3) return opn^num; 44 45 } 46 47 void update(int l,int r,int p,int opn,int op) 48 { 49 if(node[p].l==l&&node[p].r==r&&node[p].num>=0) //当找到区间并且区间被相同的数覆盖 50 { 51 node[p].num = opreate(op,opn,node[p].num); 52 return; 53 } 54 if(node[p].num>=0) //经过该区间时,向下更新 55 { 56 node[lson].num = node[rson].num = node[p].num; 57 node[p].num = -1; 58 } 59 int mid = (node[p].l+node[p].r)>>1; 60 if(r<=mid) update(l,r,lson,opn,op); 61 else if(l>mid) update(l,r,rson,opn,op); 62 else 63 { 64 update(l,mid,lson,opn,op); 65 update(mid+1,r,rson,opn,op); 66 } 67 if(node[lson].num!=-1&&node[lson].num==node[rson].num) //向上更新 68 { 69 node[p].num = node[lson].num; 70 } 71 } 72 73 __int64 query(int l,int r,int p) 74 { 75 if(node[p].l==l&&node[p].r==r&&node[p].num>=0) 76 { 77 return node[p].num*(node[p].r-node[p].l+1); 78 } 79 if(node[p].num>=0) //经过该区间时,向下更新 80 { 81 node[lson].num = node[rson].num = node[p].num; 82 node[p].num = -1; 83 } 84 int mid = (node[p].l+node[p].r)>>1; 85 if(r<=mid) return query(l,r,lson); 86 else if(l>mid) return query(l,r,rson); 87 else return query(l,mid,lson)+query(mid+1,r,rson); 88 if(node[lson].num!=-1&&node[lson].num==node[rson].num) //向上更新 89 { 90 node[p].num = node[lson].num; 91 } 92 } 93 94 int main() 95 { 96 int t; 97 scanf("%d",&t); 98 while(t--) 99 { 100 int n,m; 101 scanf("%d%d",&n,&m); 102 char op[5]; 103 building(1,n,1); 104 while(m--) 105 { 106 scanf("%s",op); 107 int opn,a,b; 108 if(op[0]=='S') 109 { 110 scanf("%d%d",&a,&b); 111 printf("%I64d\n",query(a+1,b+1,1)); 112 } 113 else 114 { 115 scanf("%d%d%d",&opn,&a,&b); 116 if(op[0]=='A') update(a+1,b+1,1,opn,1); 117 else if(op[0]=='O') update(a+1,b+1,1,opn,2); 118 else if(op[0]=='X') update(a+1,b+1,1,opn,3); 119 } 120 } 121 } 122 return 0; 123 }