POJ - 2777——Count Color(懒标记线段树二进制)

╰半夏微凉° 2022-01-06 07:41 327阅读 0赞

Count Color














Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 53639   Accepted: 16153

Description

Chosen Problem Solving and Program design as an optional course, you are required to solve all kinds of problems. Here, we get a new problem.

There is a very long board with length L centimeter, L is a positive integer, so we can evenly divide the board into L segments, and they are labeled by 1, 2, … L from left to right, each is 1 centimeter long. Now we have to color the board - one segment with only one color. We can do following two operations on the board:

  1. “C A B C” Color the board from segment A to segment B with color C.
  2. “P A B” Output the number of different colors painted between segment A and segment B (including).

In our daily life, we have very few words to describe a color (red, green, blue, yellow…), so you may assume that the total number of different colors T is very small. To make it simple, we express the names of colors as color 1, color 2, … color T. At the beginning, the board was painted in color 1. Now the rest of problem is left to your.

Input

First line of input contains L (1 <= L <= 100000), T (1 <= T <= 30) and O (1 <= O <= 100000). Here O denotes the number of operations. Following O lines, each contains “C A B C” or “P A B” (here A, B, C are integers, and A may be larger than B) as an operation defined previously.

Output

Ouput results of the output operation in order, each line contains a number.

Sample Input

  1. 2 2 4
  2. C 1 1 2
  3. P 1 2
  4. C 2 2 2
  5. P 1 2

Sample Output

  1. 2
  2. 1
  3. 题目链接:
  4. http://poj.org/problem?id=2777
  5. 题目大意:
  6. L长度的木板涂色,一开始木板颜色相同,有T种颜色可用,O(不是零是 ou )次操作。每次操作有两种情况,一种是改变木板的颜色也就是给木板的某个区间涂色,另一种是询问给定区间的颜色种类数量。
  7. 题目分析:
  8. 这题比较明显是使用线段树解决问题,但是有一个问题是:超时。那么如何解决这个问题呢,这时候就引进了一个很优秀的操作————懒标记。
  9. 懒标记是什么呢?“懒”的意思很明显了,就是说在不涉及某个节点的情况下,选择性的变懒,不去改变。举个例子:
  10. 如果改变区间的颜色,那么我们可以不去找到区间内每个叶子然后改变每个叶子的颜色,而是找到在这个区间内的另外的区间(可能是一个区间,也可能是很多个区间,也有可能包括了一个区间和n个叶子,也有可能只有叶子),把找到的区间改变颜色,并把区间懒标记。
  11. 懒标记后,如果再次查询到该节点,那么需要做下推操作,即把该节点的颜色,下推给子节点,改变子节点的颜色,并把该节点懒标记清空。
  12. 对于颜色的存储,这题还是需要注意的。我们很容易想到存储每个节点区间的颜色种类数,但是这样存储问题就来了,怎么确定子节点中颜色是否相同。所以有引进一个操作,二进制表示法。
  13. 我们可以看到颜色的种类不超过30种,所以可以用一位二进制表示一种颜色,即颜色一为(1),颜色二为(10),颜色三为(100),颜色四为(1000),依次类推。
  14. 那么我们存储父节点颜色怎么存储呢? 或操作(|)。
  15. tree[k].color=tree[k<<1].color|tree[k<<1|1].color;
  16. 解释一下:或操作,如果颜色相同,那么结果仍保存该颜色;如果子节点一个有该颜色,另一个没有该颜色,操作结果仍然有该颜色;如果两个子节点都没有该颜色,那么结果也没有该颜色。
  17. 最后得到的结果只需要判断在二进制下有几个1就可以了。
  18. 还要注意一个坑就是 AB大小不确定。
  19. AC代码如下:
  20. #include<stdio.h>
  21. const int MAX=1e6+5;
  22. struct a{
  23. int left,right;
  24. int lazy,ans;
  25. }tree[MAX<<2];
  26. void init(int length) //懒标记初始化
  27. {
  28. for(int i=1;i<=length;i++)
  29. {
  30. tree[i].lazy=0;
  31. }
  32. }
  33. void btree(int k,int l,int r) //建树操作
  34. {
  35. tree[k].left=l;tree[k].right=r;
  36. if(l==r)
  37. {
  38. tree[k].ans=1;return ;
  39. }
  40. int mid=(l+r)>>1;
  41. btree(k<<1,l,mid);
  42. btree(k<<1|1,mid+1,r);
  43. tree[k].ans=(tree[k<<1].ans|tree[k<<1|1].ans);
  44. }
  45. void push_down(int k) //下推
  46. {
  47. if(tree[k].left==tree[k].right) return ;
  48. tree[k<<1].lazy=tree[k].lazy;
  49. tree[k<<1|1].lazy=tree[k].lazy;
  50. tree[k<<1].ans=1<<(tree[k].lazy-1);
  51. tree[k<<1|1].ans=1<<(tree[k].lazy-1);
  52. tree[k].lazy=0;
  53. }
  54. void datetree(int k,int l,int r,int co) //涂色
  55. {
  56. if(tree[k].left>=l&&tree[k].right<=r)
  57. {
  58. tree[k].ans=1<<(co-1);
  59. tree[k].lazy=co;
  60. return ;
  61. }
  62. if(tree[k].lazy) push_down(k);
  63. int mid=(tree[k].left+tree[k].right)>>1;
  64. if(mid<l)
  65. {
  66. datetree(k<<1|1,l,r,co);
  67. }
  68. else if(mid>=r)
  69. {
  70. datetree(k<<1,l,r,co);
  71. }
  72. else
  73. {
  74. datetree(k<<1,l,r,co);
  75. datetree(k<<1|1,l,r,co);
  76. }
  77. tree[k].ans=(tree[k<<1].ans|tree[k<<1|1].ans);
  78. }
  79. int ans;
  80. void query(int k,int l,int r) //询问
  81. {
  82. if(tree[k].left>=l&&tree[k].right<=r)
  83. {
  84. ans=(ans|tree[k].ans);
  85. return ;
  86. }
  87. if(tree[k].lazy) push_down(k);
  88. int mid=(tree[k].left+tree[k].right)>>1;
  89. if(mid<l)
  90. {
  91. query(k<<1|1,l,r);
  92. }
  93. else if(mid>=r)
  94. {
  95. query(k<<1,l,r);
  96. }
  97. else
  98. {
  99. query(k<<1,l,r);
  100. query(k<<1|1,l,r);
  101. }
  102. }
  103. int main()
  104. {
  105. int L,color,q;
  106. char n[10];
  107. scanf("%d%d%d",&L,&color,&q);
  108. init(L);
  109. btree(1,1,L);
  110. while(q--)
  111. {
  112. scanf("%s",n);
  113. if(n[0]=='C')
  114. {
  115. int a,b,c;
  116. scanf("%d%d%d",&a,&b,&c);
  117. if(a>b){
  118. int t=a;a=b;b=t;
  119. }
  120. datetree(1,a,b,c);
  121. }
  122. else
  123. {
  124. int a,b;
  125. ans=0;
  126. int cnt=0;
  127. scanf("%d%d",&a,&b);
  128. if(a>b){
  129. int t=a;a=b;b=t;
  130. }
  131. query(1,a,b);
  132. while(ans)
  133. {
  134. if(ans%2) cnt++;
  135. ans/=2;
  136. }
  137. printf("%d\n",cnt);
  138. }
  139. }
  140. return 0;
  141. }

转载于:https://www.cnblogs.com/noback-go/p/10541560.html

发表评论

表情:
评论列表 (有 0 条评论,327人围观)

还没有评论,来说两句吧...

相关阅读