fzu 2105 Digits Count 线段树
Posted 下周LGD该赢了吧
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了fzu 2105 Digits Count 线段树相关的知识,希望对你有一定的参考价值。
题目链接:http://acm.fzu.edu.cn/problem.php?pid=2105
题意:
给出一个数组A[0]-A[n-1],每个数最大是16。有4种操作:
AND opn L R:L-R区间内的数都AND上opn这个数
OR opn L R:L-R区间内的数都OR上opn这个数
XOR opn L R:L-R区间内的数都XOR上opn这个数
SUM L R:求L-R区间内所有数的和。
0 <= opn <= 16
思路:
可以发现A[i]和opn最大都不超过16,所以可以设4个数组,分别用来存数的第0位,第1位,第2位,第3位。
对每个数组用线段树来维护。
可以知道AND 操作,如果AND 1,那么原来的那一位不变,如果AND 0,那么原来那一位变成0。
OR操作,如果OR 1,那么原来那一位变成0,如果OR 0,则原来那一位不变。
XOR操作,如果XOR 0,那么原来那位不变,如果XOR 1,原来那一位要取反。
所以成端更新就是3个操作,该段全部取反,该段全变0,该段全变1。
取反操作要特殊处理一下,
如果当前节点的标记是取反操作,如果它的子节点是变0操作,那么此时它的子节点标记的操作应该为变1。
如果它的子节点是变1操作,那么此时它的子节点标记的操作应该为变0。
如果它的子节点是取反操作,那么两次取反相当于不变。
如果它的子节点无标记,那么子节点才应该标记为取反操作。
最后求SUM的时候,把每一位上为1的数乘相应的权重加起来就可以了。
1 //#include <bits/stdc++.h> 2 #include <iostream> 3 #include <cstring> 4 #include <cstdio> 5 #include <string> 6 #include <cmath> 7 using namespace std; 8 int T; 9 #define maxn 1000010 10 #define lson l, m, rt<<1 11 #define rson m+1, r, rt<<1|1 12 int sum[5][maxn<<2], col[5][maxn<<2]; 13 void pushup(int rt) 14 { 15 for(int i = 0; i < 4; i++) sum[i][rt] = sum[i][rt<<1] + sum[i][rt<<1|1]; 16 } 17 void build(int l, int r, int rt) 18 { 19 for(int i = 0; i < 4; i++) col[i][rt] = -1; 20 if(l == r) 21 { 22 int temp; scanf("%d", &temp); 23 for(int i = 0; i < 4; i++) 24 { 25 sum[i][rt] = temp & 1; 26 temp >>= 1; 27 } 28 return; 29 } 30 int m = (l+r)>>1; 31 build(lson); 32 build(rson); 33 pushup(rt); 34 } 35 void pushdown(int rt, int len) 36 { 37 for(int i = 0; i < 4; i++) 38 { 39 if(col[i][rt] == -1) continue; 40 if(col[i][rt] == 1) 41 { 42 sum[i][rt<<1] = len-(len>>1); 43 sum[i][rt<<1|1] = len>>1; 44 col[i][rt<<1] = col[i][rt<<1|1] = 1; 45 } 46 else if(col[i][rt] == 0) 47 { 48 sum[i][rt<<1] = sum[i][rt<<1|1] = 0; 49 col[i][rt<<1] = col[i][rt<<1|1] = 0; 50 } 51 else if(col[i][rt] == 2) 52 { 53 sum[i][rt<<1] = (len-(len>>1)) - sum[i][rt<<1]; 54 sum[i][rt<<1|1] = (len>>1) - sum[i][rt<<1|1]; 55 if(col[i][rt<<1] == 1) col[i][rt<<1] = 0; 56 else if(col[i][rt<<1] == 0) col[i][rt<<1] = 1; 57 else if(col[i][rt<<1] == 2) col[i][rt<<1] = -1; 58 else col[i][rt<<1] = 2; 59 60 if(col[i][rt<<1|1] == 1) col[i][rt<<1|1] = 0; 61 else if(col[i][rt<<1|1] == 0) col[i][rt<<1|1] = 1; 62 else if(col[i][rt<<1|1] == 2) col[i][rt<<1|1] = -1; 63 else col[i][rt<<1|1] = 2; 64 } 65 col[i][rt] = -1; 66 } 67 } 68 void update(int L, int R, int val, int l, int r, int rt, int op) 69 { 70 if(L <= l && R >= r) 71 { 72 if(l < r) pushdown(rt, r-l+1); 73 int tempval = val; 74 for(int i = 0; i < 4; i++) 75 { 76 if(op == 0) // AND 77 { 78 if((tempval&1) == 0) 79 { 80 sum[i][rt] = 0; col[i][rt] = 0; 81 } 82 } 83 else if(op == 1) //OR 84 { 85 if((tempval&1) == 1) 86 { 87 sum[i][rt] = r-l+1; col[i][rt] = 1; 88 } 89 } 90 else if(op == 2) //XOR 91 { 92 if((tempval&1) == 1) 93 { 94 sum[i][rt] = (r-l+1) - sum[i][rt]; col[i][rt] = 2; 95 } 96 } 97 tempval >>= 1; 98 } 99 return; 100 } 101 pushdown(rt, r-l+1); 102 int m = (l+r)>>1; 103 if(L <= m) update(L, R, val, lson, op); 104 if(R > m) update(L, R, val, rson, op); 105 pushup(rt); 106 } 107 int query(int L, int R, int l, int r, int rt) 108 { 109 if(L <= l && R >= r) 110 { 111 int SUM = 0; 112 for(int i = 0; i < 4; i++) 113 { 114 SUM += sum[i][rt]*pow(2.0,i); 115 } 116 return SUM; 117 } 118 pushdown(rt, r-l+1); 119 int m = (l+r)>>1; 120 int ret = 0; 121 if(L <= m) ret += query(L, R, lson); 122 if(R > m) ret += query(L, R, rson); 123 return ret; 124 } 125 int main() 126 { 127 //freopen("in.txt", "r", stdin); 128 //freopen("out.txt", "w", stdout); 129 int n, m; 130 scanf("%d", &T); 131 while(T--) 132 { 133 scanf("%d%d", &n, &m); 134 build(1, n, 1); 135 char op[10]; 136 int opn, l, r; 137 while(m--) 138 { 139 scanf("%s", op); 140 if(op[0] == ‘A‘) 141 { 142 scanf("%d%d%d", &opn, &l, &r); 143 update(l+1, r+1, opn, 1, n, 1, 0); 144 } 145 else if(op[0] == ‘O‘) 146 { 147 scanf("%d%d%d", &opn, &l, &r); 148 update(l+1, r+1, opn, 1, n, 1, 1); 149 } 150 else if(op[0] == ‘X‘) 151 { 152 scanf("%d%d%d", &opn, &l, &r); 153 update(l+1, r+1, opn, 1, n, 1, 2); 154 } 155 else if(op[0] == ‘S‘) 156 { 157 scanf("%d%d", &l, &r); 158 printf("%d\n", query(l+1, r+1, 1, n, 1)); 159 } 160 } 161 162 } 163 return 0; 164 }
以上是关于fzu 2105 Digits Count 线段树的主要内容,如果未能解决你的问题,请参考以下文章
FZU 2105 Digits Count(按位维护线段树)
FZU2105 Digits Count(按位建线段树)题解