Count Color
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 29895 | Accepted: 8919 |
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.
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
題意:長度為n(1~100000)個單位的畫板,有t(1~30,位運算的可能性)種顏料。現在叫你完成m組操作:
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).
思路:很經典的線段樹。學習到了很多的新知識,最重要的是三點:1.延遲覆蓋的操作。2.位操作,用 | 來合並顏色種類。3.updata操作時遞歸回來,兩個子節點的信息對父節點的更新。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=100010; #define L(rt) (rt<<1) #define R(rt) (rt<<1|1) struct Tree{ int l,r; int col; // 用一個32位的int型,每一位對應一種顏色,用位運算代替bool col[32] bool cover; // 表示這個區間都被塗上同一種顏色,線段樹效率的體現,否則插入就是0(n)了。 }tree[N<<2]; void PushUp(int rt){ // 最后遞歸回來再更改父節點的顏色 tree[rt].col=tree[L(rt)].col | tree[R(rt)].col; } void build(int L,int R,int rt){ tree[rt].l=L; tree[rt].r=R; tree[rt].col=1; // 開始時都為塗有顏色1,看題要仔細,要注意狀態。 tree[rt].cover=1; if(tree[rt].l==tree[rt].r) return ; int mid=(L+R)>>1; build(L,mid,L(rt)); build(mid+1,R,R(rt)); } void PushDown(int rt){ // 延遲覆蓋的操作 tree[L(rt)].col=tree[rt].col; tree[L(rt)].cover=1; tree[R(rt)].col=tree[rt].col; tree[R(rt)].cover=1; tree[rt].cover=0; } void update(int val,int L,int R,int rt){ if(L<=tree[rt].l && R>=tree[rt].r){ tree[rt].col=val; tree[rt].cover=1; return ; } if(tree[rt].col==val) //剪枝 return ; if(tree[rt].cover) PushDown(rt); int mid=(tree[rt].l+tree[rt].r)>>1; if(R<=mid) update(val,L,R,L(rt)); else if(L>=mid+1) update(val,L,R,R(rt)); else{ update(val,L,mid,L(rt)); update(val,mid+1,R,R(rt)); } PushUp(rt); // 最后遞歸回來再更改父節點的顏色 } int sum; void query(int L,int R,int rt){ if(L<=tree[rt].l && R>=tree[rt].r){ sum |= tree[rt].col; return ; } if(tree[rt].cover){ // 這個區間全部為1種顏色,就沒有繼續分割區間的必要了 sum |= tree[rt].col; // 顏色種類相加的位運算代碼 return; } int mid=(tree[rt].l+tree[rt].r)>>1; if(R<=mid) query(L,R,L(rt)); else if(L>=mid+1) query(L,R,R(rt)); else{ query(L,mid,L(rt)); query(mid+1,R,R(rt)); } } int solve(){ int ans=0; while(sum){ if(sum&1) ans++; sum>>=1; } return ans; } void swap(int &a,int &b){ int tmp=a;a=b;b=tmp; } int main(){ //freopen("input.txt","r",stdin); int n,t,m; while(~scanf("%d%d%d",&n,&t,&m)){ build(1,n,1); char op[3]; int a,b,c; while(m--){ scanf("%s",op); if(op[0]=='C'){ scanf("%d%d%d",&a,&b,&c); if(a>b) swap(a,b); update(1<<(c-1),a,b,1); // int型的右起第c位變為1,即2的c-1次方。 }else{ scanf("%d%d",&a,&b); if(a>b) swap(a,b); sum=0; query(a,b,1); printf("%d\n",solve()); } } } return 0; }