当前位置:   article > 正文

ACM: FZU 2105 Digits Count - 位运算的线段树【黑科技福利】

卡空间黑科技线段树
  FZU 2105  Digits Count
Time Limit:10000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u

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

For each test case and for each "SUM" operation, please output the result with a single line.

Sample Input

1
4 4
1 2 4 7
SUM 0 2
XOR 5 0 0
OR 6 0 3
SUM 0 2

Sample Output

7
18

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种操作。

AND opn l r   对 l~r 段的数与 opn 进行&运算;

OR opn l r 对 l~r 段的数与 opn 进行|运算;

XOR opn l r 对 l~r 段的数与 opn 进行^运算;

SUMl r 对 l~r 段的数求和,并输出。

很明显的线段树,可是我还是太年轻。一开始以为只是一棵裸树,结果写到一半,发现不能对求和的数再进行与或非的运算,也不知道我哪里来的勇气,想到,既然不能对和去运算,不如把lazy全压下去。。。MDZZ。。。

后来,队友提示我可以用二进制来存数,然后与或非的情况也就变得特别简单了。

然后就用关于二进制的线段树来写了这个,思路一开始是很混乱的,不过写到后面还是被  >>  和 <<  坑了好久,还是修行不精啊。。。

A了但是运行时间还是比较久。

最后集训队队长发了个福利,读入优化,速度爆炸了,又是我的代码运行速度第一(233333)。

AC代码:
/*/
  1. #include"algorithm"
  2. #include"iostream"
  3. #include"cstring"
  4. #include"cstdlib"
  5. #include"cstdio"
  6. #include"string"
  7. #include"vector"
  8. #include"stack"
  9. #include"queue"
  10. #include"cmath"
  11. #include"map"
  12. using namespace std;
  13. typedef long long LL ;
  14. #define lson l,m,rt<<1
  15. #define rson m+1,r,rt<<1|1
  16. #define FK(x) cout<<"["<<x<<"]\n"
  17. #define memset(x,y) memset(x,y,sizeof(x))
  18. #define memcpy(x,y) memcpy(x,y,sizeof(x))
  19. #define smallfor(T) for(int i=0 ;i<T ;i++)
  20. #define bigfor(T) for(int qq=1;qq<= T ;qq++)
  21. const int MX =1111111;
  22. const int INF=0x3f3f3f3f;
  23. int sum[MX<<2][4],lazy[MX<<2][4];
  24. void PushUp(int rt,int i) {
  25. sum[rt][i]=sum[rt<<1][i]+sum[rt<<1|1][i];
  26. }
  27. void PushDown(int rt,int m,int i) {
  28. if(lazy[rt][i]==0) { //如果进行了AND操作,并且该位为0 清空下面子树。
  29. lazy[rt<<1][i]=0;
  30. lazy[rt<<1|1][i]=0;
  31. sum[rt<<1][i]=sum[rt<<1|1][i]=0;
  32. }
  33. if(lazy[rt][i]==1) { //如果进行了OR 操作,并且该位为1 填满下面子树。
  34. lazy[rt<<1][i]=1;
  35. lazy[rt<<1|1][i]=1;
  36. sum[rt<<1][i]=m-(m>>1);
  37. sum[rt<<1|1][i]=m>>1;
  38. }
  39. if(lazy[rt][i]==2) { //如果进行了XOR操作
  40. if(lazy[rt<<1][i]==INF) { //如果没有进行过任何操作,标记为XOR操作
  41. lazy[rt<<1][i]=2;
  42. sum[rt<<1][i]=m-(m>>1)-sum[rt<<1][i];
  43. } else if(lazy[rt<<1][i]==2) { //如果进行过XOR操作,a^b^b==a 恢复操作内容。
  44. lazy[rt<<1][i]=INF;
  45. sum[rt<<1][i]=m-(m>>1)-sum[rt<<1][i];
  46. } else { //如果进行了操作并且不是XOR操作 将该操作再取XOR操作
  47. lazy[rt<<1][i]^=1;
  48. if(lazy[rt<<1][i]==0) sum[rt<<1][i]=0;
  49. else sum[rt<<1][i]=m-(m>>1);
  50. }
  51. // 另一棵子树用同样的方法处理
  52. if(lazy[rt<<1|1][i]==INF) {
  53. lazy[rt<<1|1][i]=2;
  54. sum[rt<<1|1][i]=(m>>1)-sum[rt<<1|1][i];
  55. } else if(lazy[rt<<1|1][i]==2) {
  56. lazy[rt<<1|1][i]=INF;
  57. sum[rt<<1|1][i]=(m>>1)-sum[rt<<1|1][i];
  58. } else {
  59. lazy[rt<<1|1][i]^=1;
  60. if(lazy[rt<<1|1][i]==0) sum[rt<<1|1][i]=0;
  61. else sum[rt<<1|1][i]=(m>>1);
  62. }
  63. }
  64. lazy[rt][i]=INF; //标记lazy为空
  65. }
  66. void Build(int l,int r,int rt) {
  67. for(int i=0; i<4; i++) lazy[rt][i]=INF; //清空懒惰标记
  68. if(r==l) {
  69. int temp;
  70. scanf("%d",&temp);
  71. // FK("temp=="<<temp);
  72. for(int i=0; i<4; i++) {
  73. sum[rt][i]=(bool)(temp&(1<<i));//【这里一定要取(bool)否则得到的值不会是1,而是比 1大的数】
  74. // 该题目的方法是用sum保存每个位上值的总数,再改变为10进制,求和。
  75. // 把数按照二进制保存在4个位上面
  76. // FK(sum[rt][i]);
  77. }
  78. return;
  79. }
  80. int m=(r+l)>>1;
  81. Build(lson);
  82. Build(rson);
  83. for(int i=0; i<4; i++) PushUp(rt,i);
  84. }
  85. void UpData(int L,int R,int v,int i,int l,int r,int rt) {
  86. if(r<=R&&L<=l) {
  87. switch(v) {
  88. case 0:
  89. sum[rt][i]=0,lazy[rt][i]=v;
  90. //如果是进行AND操作,并且是0,清空和。
  91. break;
  92. case 1:
  93. sum[rt][i]=r-l+1,lazy[rt][i]=v;
  94. //如果是进行OR 操作,并且是1,填满和。
  95. break;
  96. case 2:
  97. sum[rt][i]=r-l+1-sum[rt][i];
  98. if(lazy[rt][i]==2) lazy[rt][i]=INF;
  99. else if(lazy[rt][i]==INF) lazy[rt][i]=2;
  100. else lazy[rt][i]^=1;
  101. break;
  102. default:
  103. break;
  104. }
  105. return ;
  106. }
  107. PushDown(rt,r-l+1,i);
  108. int m=(r+l)>>1;
  109. if(L<=m)UpData(L,R,v,i,lson);
  110. if(R>m) UpData(L,R,v,i,rson);
  111. PushUp(rt,i);
  112. }
  113. int Query(int L,int R,int i,int l,int r,int rt) {
  114. if(L<=l&&r<=R) {
  115. return sum[rt][i];
  116. // 返回这个数该位的和。
  117. }
  118. int m=(r+l)>>1;
  119. int sum=0;
  120. PushDown(rt,r-l+1,i);
  121. if(L<=m)sum+=Query(L,R,i,lson);
  122. if(R>m) sum+=Query(L,R,i,rson);
  123. return sum;
  124. }
  125. int main() {
  126. int T;
  127. scanf("%d",&T);
  128. bigfor(T) {
  129. int n,m;
  130. scanf("%d%d",&n,&m);
  131. char op[5];
  132. Build(0,n-1,1);
  133. // FK("Build Success!");
  134. for(int i=0; i<m; i++) {
  135. scanf("%s",op);
  136. if(op[0]=='S') {
  137. int l,r;
  138. int ans=0;
  139. scanf("%d%d",&l,&r);
  140. for(int j=0; j<4; j++) ans+=Query(l,r,j,0,n-1,1)<<j;
  141. // 将每一位的数字和用10进制进位后相加。
  142. printf("%d\n",ans);
  143. } else {
  144. int opn,l,r;
  145. char v;
  146. scanf("%d%d%d",&opn,&l,&r);
  147. if(op[0]=='A') { //AND为&如果某位上为 1 那么值不变 否则全变为0;【区间覆盖】
  148. for(int j=0; j<4; j++) {
  149. int x=opn&(1<<j);
  150. // FK("j=="<<j<<" x=="<<x);
  151. if(!x)UpData(l,r,0,j,0,n-1,1);
  152. }
  153. }
  154. if(op[0]=='O') { //OR 为|如果某位上为 0 那么值不变 否则全变为1;【区间覆盖】
  155. for(int j=0; j<4; j++) {
  156. int x=opn&(1<<j);
  157. // FK("j=="<<j<<" x=="<<x);
  158. if(x)UpData(l,r,1,j,0,n-1,1);
  159. }
  160. }
  161. if(op[0]=='X') { //XOR为^如果某位上为 0 那么值不变 否则0->1,1->0【区间更新】
  162. for(int j=0; j<4; j++) {
  163. int x=opn&(1<<j);
  164. // FK("j=="<<j<<" x=="<<x);
  165. if(x)UpData(l,r,2,j,0,n-1,1);
  166. }
  167. }
  168. }
  169. }
  170. }
  171. return 0;
  172. }
 
      

    

//下面是快速读入的福利【只适用于读入比较多的题目,适用于题目原本复杂度为O(n),但是自己的代码估计会是O(nlog(n)),这个优化的作用就会比较明显。】

//下面就是黑科技:

  1. namespace IO {
  2. const int MT = 5e7; //1e711000kb
  3. char buf[MT];
  4. int c, sz;
  5. void begin() {
  6. c = 0;
  7. sz = fread(buf, 1, MT, stdin);
  8. }
  9. inline bool read(int &t) {
  10. while(c < sz && buf[c] != '-' && (buf[c] < '0' || buf[c] > '9')) c++;
  11. if(c >= sz) return false;
  12. bool flag = 0;
  13. if( buf[c] == '-')flag = 1, c++;
  14. for(t = 0; c < sz && '0' <= buf[c] && buf[c] <='9'; c++) t = t * 10 + buf[c] - '0';
  15. if(flag) t = -t;
  16. return true;
  17. } inline bool read(char s[]) {
  18. while(c < sz && (buf[c] == ' ' || buf[c] == '\n')) c++;
  19. if(c >= sz) return false;
  20. int len = 0;
  21. while(c < sz && buf[c] != ' ' && buf[c] != '\n') s[len++] = buf[c] , c++;
  22. s[len]=0;
  23. return true;
  24. }
  25. }
  26. using namespace IO;
  27. //打开方式:
  28. int x;
  29. read(x);
 
      

  

 
 
      

  

 

 

转载于:https://www.cnblogs.com/HDMaxfun/p/5793956.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/180160
推荐阅读
相关标签
  

闽ICP备14008679号

        
cppcmd=keepalive&