线段树,区间更新,位运算: poj2777Count Color

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,刚开始的时候并没有想到要用到位运算,结果傻了吧唧的去开了一个数组储存状态,结果就在各种改变状态的时候,就非常开心的超时了;
2,cover数组非常重要,充分的体现了线段树的优势,如果区间的颜色一样,则在没有必要划分区间;
3,用二进制位来保存颜色的状态非常棒(看到颜色不超过30中的时候就应该想到这个的嘛,题做少了,不够敏感),既节省了存储空间,又方便后面的状态变换~

#include 
#include 
#include 
#include 
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int maxn=100009;
int n,cover[maxn<<2],color[maxn<<2];//cover标记此区间是否是同一种颜色,color表示此区间的颜色状态,
//由于颜色不超过30种,故可以用int的每一位来表示颜色,相比于开一个数组要方便得多
int temp;
int L,T,O;

void pushup(int rt)
{
  color[rt]=color[rt<<1]|color[rt<<1|1];//位运算很高效!
}
void pushdown(int rt)
{
    if(cover[rt])
    {
        cover[rt<<1]=cover[rt<<1|1]=cover[rt];
        color[rt<<1]=color[rt<<1|1]=color[rt];
        cover[rt]=0;
    }
}
void build(int l,int r,int rt)
{
    color[rt]=1;
    cover[rt]=1;
    if(l==r)
        return ;
    int m=l+r>>1;
    build(lson);
    build(rson);
}
void update(int L,int R,int c,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        cover[rt]=1;
        color[rt]=c;
        return;
    }
    if(color[rt]==c)//如果此时的状态和要改变的状态一样则没有必要再进行下去
        return;
    int m=l+r>>1;
    pushdown(rt);
    if(L<=m) update(L,R,c,lson);
    if(R>m) update(L,R,c,rson);
    pushup(rt);
}
void query(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        temp|=color[rt];
        return;
    }
    if(cover[rt])
    {
        temp|=color[rt];//如果颜色一样则没有必要继续划分区间,很重要哦~
        return;
    }
    int m=l+r>>1;
    pushdown(rt);
    if(m>=L) query(L,R,lson);
    if(mint main()
{
    scanf("%d%d%d",&L,&T,&O);
    build(1,L,1);
    while(O--)
    {
        char ch[10];
        int a,c,b;
        scanf("%s",ch);
        if(ch[0]=='C')
        {
            scanf("%d%d%d",&a,&b,&c);
            if(a>b) swap(a,b);
            update(a,b,1<<(c-1),1,L,1);
        }
        else
        {
            scanf("%d%d",&a,&b);
            if(a>b) swap(a,b);
            temp=0;
            query(a,b,1,L,1);
            int sum=0;
            while(temp)
            {
                if(temp&1)
                    sum++;
                 temp>>=1;
            }
            printf("%d\n",sum);
        }
    }
    return 0;
}

你可能感兴趣的:(线段树,数据结构与算法)