POJ 2777 Count Color(线段树+二进制状态压缩)
Time Limit: 1000MS | Memory Limit: 65536K | |
---|---|---|
Total Submissions: 49947 | Accepted: 15046 |
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:
- “C A B C” Color the board from segment A to segment B with color C.
- “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
题意
有个木板被分成了L份,现在给出T种颜色来上色(1-T代表T种颜色),接下来有O个操作,每个操作占一行。对于每组操作,如果首字符是’C’,则将区间[A,B]的木块全染成C色(注意这里的A不一定小于B);对于首字母是’P’,输出区间[A,B]有多少种不同的颜色。
解题思路
很显然,涉及到区间查询和区间更改可以直接用线段树来实现。因为题目给的颜色范围很小,所以开始的时候我用的一个二维数组来存每个节点的状态,结果TLE,后台数据有点硬。后来想到了用二进制状态压缩代替二维数组,这样就省去了二维数组的操作的时间,最后查询的时候直接做或运算。注意更新线段树的时候,找到应当节点时,可以直接将其的改成新状态,因其只有一种颜色,所以可以直接进行赋值2^color(通过位运算实现)。对于上推操作,直接由两个子节点进行或运算;对于下推操作,这里需要用到懒惰数组,直接赋为懒惰数组的值即可。
代码
#include<iostream>
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
const int maxn = 1e6+5;
int arr[maxn<<2],Add[maxn<<2],ans;
int n,t,q;
void pushup(int rt)
{
arr[rt]=arr[rt<<1]|arr[rt<<1|1];
}
void build(int l,int r,int rt)
{
if(l==r)
{
arr[rt]=1<<1;
return;
}
int mid=(l+r)>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
pushup(rt);
}
void pushdown(int rt)
{
if(Add[rt])
{
Add[rt<<1]=Add[rt<<1|1]=Add[rt];
arr[rt<<1]=arr[rt<<1|1]=1<<Add[rt];
Add[rt]=0;
}
}
void update(int L,int R,int color,int l,int r,int rt)
{
if(L<=l&&R>=r)
{
arr[rt]=1<<color;
Add[rt]=color;
return;
}
int mid=(l+r)>>1;
pushdown(rt);
if(L<=mid) update(L,R,color,l,mid,rt<<1);
if(R >mid) update(L,R,color,mid+1,r,rt<<1|1);
pushup(rt);
}
void query(int L,int R,int l,int r,int rt)
{
if(L<=l&&R>=r)
{
ans|=arr[rt];
return;
}
int mid=(l+r)>>1;
pushdown(rt);
if(L<=mid) query(L,R,l,mid,rt<<1);
if(R> mid) query(L,R,mid+1,r,rt<<1|1);
}
int main()
{
// freopen("in.txt","r",stdin);
scanf("%d%d%d",&n,&t,&q);
build(1,n,1);
while(q--)
{
getchar();
char op=getchar();
int x,y,z;
if(op=='C')
{
scanf("%d%d%d",&x,&y,&z);
if(x>y) swap(x,y);
update(x,y,z,1,n,1);
}
else
{
scanf("%d%d",&x,&y);
if(x>y) swap(x,y);
ans=0;
query(x,y,1,n,1);
int anss=0;
while(ans)
{
if(ans&1) anss++;
ans/=2;
}
printf("%d\n",anss);
}
}
return 0;
}