[poj2777] Count Color(线段树+状压)

题目大意

描述

给一块长为L的长板染色,有两种操作:
1.“C A B C”用颜色C将板从A段着色到B段。
2.“P A B”输出A段和B段(包括A和B)之间的不同颜色的数量。

输入

第一行输入包含L(1 <= L <= 100000),T(1 <= T <= 30)和O(1 <= 0 <= 100000)。这里O表示操作次数。后O行,每行包含“C A B C”或“P A B”(这里A,B,C是整数,并且A可以大于B)。

输出

按顺序输出“P”操作结果,每行包含一个数字。

样例输入
2 2 4
C 1 1 2
P 1 2
C 2 2 2
P 1 2
样例输出
2
1

解题思路

用线段树维护染色操作。
线段树每个节点维护两个值,colo和lazy。colo表示此节点表示区间的颜色集合(二进制状压),lazy为区间覆盖标记。
pushup时,当前结点的colo即左右儿子的colo相或的值。
复杂度 O(nlogn)

Code

#include<cstdio>

#define lid id<<1
#define rid id<<1|1
#define mid ((tr[id].l+tr[id].r)>>1)

using namespace std;

inline int read(){
    int x = 0;
    bool fl = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if(ch == '-')   fl = 0;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = (x << 1) + (x << 3) + ch - '0';
        ch = getchar();
    }
    return fl ? x : -x;
}

const int N = 100005;
int n, t, q, a, b, c, ans;
char opt[2];

inline int lowbit(int x){ return x & -x; }
inline int countOne(int x){
    int cnt = 0;
    while(x){
        cnt++;
        x -= lowbit(x);
    }
    return cnt;
}

struct seg_tree{
    int l, r, colo;
    bool lazy;
}tr[N<<2];

void pushup(int id){
    tr[id].colo = tr[lid].colo | tr[rid].colo;
}

void pushdown(int id){
    if(tr[id].l != tr[id].r && tr[id].lazy){
        tr[lid].colo = tr[rid].colo = tr[id].colo;
        tr[lid].lazy = tr[rid].lazy = 1;
        tr[id].lazy = 0;
    }
}

void build(int id, int l, int r){
    tr[id].l = l, tr[id].r = r;
    tr[id].colo = (1 << 1);
    tr[id].lazy = 1;
    if(tr[id].l == tr[id].r)    return;
    build(lid, l, mid);
    build(rid, mid+1, r);
    pushup(id);
}

void modify(int id, int l, int r, int c){
    pushdown(id);
    if(tr[id].l == l && tr[id].r == r){
        tr[id].colo = (1 << c);
        tr[id].lazy = 1;
        return;
    }
    if(r <= mid)    modify(lid, l, r, c);
    else if(l > mid)    modify(rid, l, r, c);
    else    modify(lid, l, mid, c), modify(rid, mid+1, r, c);
    pushup(id);
}

void query(int id, int l, int r){
    pushdown(id);
    if(tr[id].l == l && tr[id].r == r){
        ans |= tr[id].colo;
        return;
    }
    if(r <= mid)    query(lid, l, r);
    else if(l > mid)    query(rid, l, r);
    else    query(lid, l, mid), query(rid, mid+1, r);
}

int main(){
    n = read(), t = read(), q = read();
    build(1, 1, n);
    while(q--){
        scanf("%s", opt);
        a = read(), b = read();
        if(a > b)   a ^= b, b ^= a, a ^= b;
        if(opt[0] == 'C'){
            c = read();
            modify(1, a, b, c);
        }
        else if(opt[0] == 'P'){
            ans = 0;
            query(1, a, b);
            printf("%d\n", countOne(ans));
        }
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值