首页 > 技术文章 > POJ2777 Count Color

Exbilar 2017-02-11 15:46 原文

Count Color

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 44503   Accepted: 13494

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

 

  题目大意:有一块木板分为许多段,它们开始的时候是同一个颜色,现在有两种操作:1.将区间$[l,r]$涂成一种颜色。2.询问区间$[l,r]$中共有多少种不同的颜色。

  这看起来就像一道线段树的题(其实它本身也是),但是它与其它题目最不同的地方就在于对颜色状态的记录,如果单纯用加法去将每段区间内不同的颜色加起来,这个想法似乎比较对,但是在实现上会有障碍,因为我们不方便记录下到底有多少种不同的颜色,在统计时就会遇到障碍。于是我们可以会有一种奇怪的想法:可不可以用二进制串来描述每个区间涂色的状态呢(其实这也是套路)?答案当然是可以的,我们可设一个二进制串它的第$i$位表示第$i$种颜色是否在这个区间上,例如0011表示该区间中1号和2号颜色都被填涂了。那么我们就可以用位运算来处理状态了。在将子节点的信息分布给根节点时只有$or$一下就行了。最后查找答案时得到的也是一个二进制串,我们只要统计二进制串中的1就可以了。

代码如下:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 
 6 static const int maxm=1e6+10;
 7 
 8 int tr[maxm],lz[maxm],left[maxm],right[maxm];
 9 
10 void build(int num,int l,int r){
11     left[num]=l;right[num]=r;
12     if(l==r){tr[num]=1;return;}
13     int mid=(l+r)>>1;
14     build(num<<1,l,mid);
15     build(num<<1|1,mid+1,r);
16     tr[num]=tr[num<<1]|tr[num<<1|1];
17 }
18 
19 void pushdown(int num){
20     if(lz[num]){
21         tr[num<<1]=tr[num];tr[num<<1|1]=tr[num];
22         lz[num<<1]=1;lz[num<<1|1]=1;
23         lz[num]=0;
24     }
25 }
26 
27 void update(int num,int l,int r,int val){
28     if(left[num]>=l&&right[num]<=r){
29         lz[num]=1;tr[num]=val;
30         return;
31     }
32     if(left[num]>r||right[num]<l)return;
33     pushdown(num);
34     update(num<<1,l,r,val);
35     update(num<<1|1,l,r,val);
36     tr[num]=tr[num<<1]|tr[num<<1|1];
37 }
38 
39 int Query(int num,int l,int r){
40     if(left[num]>=l&&right[num]<=r)return tr[num];
41     if(left[num]>r||right[num]<l)return 0;
42     int ret=0;pushdown(num);
43     ret|=Query(num<<1,l,r);ret|=Query(num<<1|1,l,r);
44     return ret;
45 }
46 
47 int main(){
48     int n,t,m;
49     while(scanf("%d%d%d",&n,&t,&m)!=EOF){
50         build(1,1,n);
51         while(m--){
52             char s[5];
53             scanf("%s",s);
54             if(s[0]=='C'){
55                 int a,b,c;
56                 scanf("%d%d%d",&a,&b,&c);
57                 if(a>b)swap(a,b);
58                 update(1,a,b,1<<(c-1));
59             }else{
60                 int a,b,ans=0;
61                 scanf("%d%d",&a,&b);
62                 if(a>b)swap(a,b);
63                 int sum=Query(1,a,b);
64                 while(sum){
65                     if(sum&1)ans++;
66                     sum>>=1;
67                 }
68                 printf("%d\n",ans);
69             }
70         }    
71     }
72     
73     return 0;
74 }
View Code

 

AC通道:http://poj.org/problem?id=2777

 

推荐阅读