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(按位建线段树)题解

FZU-2105 Digits Count (两种标记成段更新)

FZU 2105 Digits Count(位数计算)

FZU-1921 栀子花开(线段树)

FZU 2297 Number theory线段树/单点更新/思维