# poj 2777 Count Color - 线段树 - 位运算优化

 Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 42472 Accepted: 12850

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

2 2 4
C 1 1 2
P 1 2
C 2 2 2
P 1 2

Sample Output

2
1

Source

讲讲题目大意（反正很多单词我也不懂）

有一个板子长L厘米，以1cm为单位进行涂色，一共有T种颜色，木板初始的颜色是

1. "C A B C"  将[a,b]涂成颜色C（涂色是覆盖）
2. "P A B" 输出[a,b]不同的颜色

初看这道题觉得可能是用线段树做，于是想出了如下几个问题

1.每个区间存储什么？

2.pushUppushDown怎么更新

第一问比较好解决，就存颜色的信息，如果说存颜色的种数（查完就完了），有一

这样就好了，定个bool数组，更新的时候就合并，另外又出现了一个无法避免的问题——

就这样第一问就解决了，那怎么更新呢？总不可能相加，位运算中有一个运算是|（或运算）

//假设有4种颜色
[1,3] 0 1 1 0
[4,5] 1 0 1 0

通过or运算后：

[1,5] 1 1 1 0

都不用考虑重复的问题了

pushUp就用这个来，将左右子树上的颜色信息相or就得到了父节点的颜色信息

结合则来考虑一下pushDown 查询区间的时候，应该是把节点上的区间完全

node->xxx->painted = 1 << (node->state - 1)

（xxx表示左子树或者右子树，state是延时标记，painted是颜色信息）

如果不知道左移运算的可以看看下面

a = 0 0 0 0 1

a << 2 = 0 0 1 0 0

a = 0 0 0 0 0

这里左移的意义在于将1（有这种颜色）移动到这种颜色对应的位置上，不然会发生可怕

这些问题解决了，这道题也就可以做出来了

附上算得超级慢的源代码:

  1 /**
2  * poj.org
3  * Problem#2777
4  * Aceepted
5  * Time:735ms
6  * Memory:9628k
7  */
8 #include<iostream>
9 #include<cstdio>
10 using namespace std;
11 typedef class TreeNode{
12     private:
13         void init(){        //成员初始化
14             painted = 0;
15             state = 0;
16             left = NULL;
17             right = NULL;
18         }
19     public:
20         /**
21          * 用二进制来表示这一段涂过的颜色，
22          * 1表示涂了的颜色，0表示没有涂的
23          * 颜色 。用第i位表示第i种颜色
24          */
25         int painted;
26         int state;            //延时标记,更新第i种颜色
27         int from;
28         int end;
29         TreeNode* left;
30         TreeNode* right;
31         TreeNode(){    init();        }
32         TreeNode(int from, int end){
33             init();
34             this->from = from;
35             this->end = end;
36         }
37 }TreeNode;
38 typedef class Tree{
39     public:
40         TreeNode* root;
41         Tree():root(NULL){}
42         Tree(int size){
43             root = build(root, 1, size);
44         }
45         void pushUp(TreeNode* node){
46             node->painted = node->left->painted | node->right->painted;
47         }
48         void pushDown(TreeNode* node){
49
50             node->left->state = node->state;
51             node->left->painted = 1 << (node->state - 1);
52
53             node->right->state = node->state;
54             node->right->painted = 1 << (node->state - 1);
55
56             node->state = 0;
57
58         }
59         TreeNode* build(TreeNode *root, int from, int end){
60             root = new TreeNode(from, end);
61             if(from == end){
62                 root->painted = 0x01;
63                 return root;
64             }
65             int mid = (from + end) >> 1;
66             root->left = build(root->left, from, mid);
67             root->right = build(root->right, mid + 1, end);
68             pushUp(root);
69             return root;
70         }
71         void update(TreeNode* now, int from, int end, int value){
72             if( from <= now->from && end >= now->end ){
73                 now->state = value;
74                 now->painted = 1 << (value - 1);
75                 return ;
76             }
77             if(now->state != 0) pushDown(now);
78             int mid = (now->from + now->end) >> 1;
79             if(end <= mid) update(now->left, from, end, value);
80             else if(from > mid) update(now->right, from, end, value);
81             else{
82                 update(now->left, from, mid, value);
83                 update(now->right, mid + 1, end, value);
84             }
85             pushUp(now);
86         }
87         int query(TreeNode* now, int from, int end){
88             if( from <= now->from && end >= now->end )    return now->painted;
89             if(now->state != 0) pushDown(now);
90             int mid = (now->from + now->end) >> 1;
91             if(end <= mid) return query(now->left, from, end);
92             else if(from > mid) return query(now->right, from, end);
93             else{
94                 return query(now->left, from, mid) | query(now->right, mid + 1, end);
95             }
96         }
97 }Tree;
98 Tree board;
99 int len,color,n;
100 char ch;
101 int a,b,c;
102 void _swap(int& a,int& b){
103     int t = a;
104     a = b;
105     b = t;
106 }
107 int getSum(int x){
108     int result = 0;
109     x &= (1 << color) - 1;
110     while(x != 0){
111         result++;
112         x -= x&(-x);
113     }
114     return result;
115 }
116 int main(){
117     scanf("%d%d%d",&len,&color,&n);
118     board = Tree(len);
119     for(int i = 1;i <= n;i++){
120         cin>>ch;
121         if(ch == 'C'){
122             scanf("%d%d%d",&a,&b,&c);
123             board.update(board.root, a, b, c);
124         }else{
125             scanf("%d%d",&a,&b);
126             if(a > b)  _swap(a,b);
127             int x = board.query(board.root, a, b);
128             printf("%d\n",getSum(x));
129         }
130     }
131     return 0;
132 }

posted @ 2016-07-13 15:17  阿波罗2003  阅读(...)  评论(...编辑  收藏