POJ 2777 Count Color(线段树+二进制状态压缩)

POJ 2777 Count Color(线段树+二进制状态压缩)

Time Limit: 1000MSMemory Limit: 65536K
Total Submissions: 49947Accepted: 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:

  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

题意

  有个木板被分成了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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值