[POJ 2777]Count 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

Solution


线段树,区间染色
因为颜色T值较小,可用位运算优化

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#define MAXN 100000
using namespace std;
int l,t,o;
struct Node
{
    int left,right,col,lazy;
}segt[MAXN*4];
void build(int idx,int a,int b)
{
    segt[idx].col=1;
    segt[idx].left=a;
    segt[idx].right=b;
    segt[idx].lazy=0;
    if(a==b)return;
    int mid=(a+b)/2;
    build(idx*2,a,mid);
    build(idx*2+1,mid+1,b);
}
void update(int idx,int a,int b,int c)
{
    if(a<=segt[idx].left&&b>=segt[idx].right)
    {
        segt[idx].col=c;
        if(segt[idx].left!=segt[idx].right)
        segt[idx].lazy=1;
        return;
    }
    if(segt[idx].lazy)
    {
        segt[idx*2].col=segt[idx*2+1].col=segt[idx].col;
        segt[idx*2].lazy=segt[idx*2+1].lazy=1;
        segt[idx].lazy=0;
    }
    int mid=(segt[idx].left+segt[idx].right)/2;
    if(a>mid)update(idx*2+1,a,b,c);
    else if(b<=mid)update(idx*2,a,b,c);
    else
    {
        update(idx*2+1,a,b,c);
        update(idx*2,a,b,c);
    }
    segt[idx].col=segt[idx*2+1].col|segt[idx*2].col;
}
int query(int idx,int a,int b)
{
    if((a<=segt[idx].left&&b>=segt[idx].right)||segt[idx].lazy)
    return segt[idx].col;
    int mid=(segt[idx].left+segt[idx].right)/2;
    if(a>mid)return query(idx*2+1,a,b);
    if(b<=mid)return query(idx*2,a,b);
    return query(idx*2+1,a,b)|query(idx*2,a,b);
}
int count(int x)
{
    int cnt=0;
    while(x)
    {
        if(x&1)cnt++;
        x>>=1;
    }
    return cnt;
}
int main()
{
    while(~scanf("%d%d%d",&l,&t,&o))
    {
        build(1,1,l);
        char opt;
        int a,b,c;
        for(int i=1;i<=o;i++)
        {
            cin>>opt;
            if(opt=='C')
            {
                scanf("%d%d%d",&a,&b,&c);
                if(a>b)swap(a,b);
                update(1,a,b,1<<(c-1));
            }
            else if(opt=='P')
            {
                scanf("%d%d",&a,&b);
                if(a>b)swap(a,b);
                int res=query(1,a,b);
                res=count(res);
                printf("%d\n",res);
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值