P1558 色板游戏 状压线段树

P1558 色板游戏 状压线段树

题面 洛谷P1558

每次不同颜色覆盖一段区间,每次询问一段区间有多少种颜色

因为颜色数\(T\)很小,使用二进制表示状态当前区间有那些颜色,二进制第\(i\)位表示此区间是否含有\(i\)这种颜色,线段树合并信息时左右儿子信息或一下就好了。

scanf读入char炸了我好久,最后换成cinAC

AC Code:

#include <iostream>
#define MAXN 100010
#define sl (x<<1)
#define sr (x<<1|1)
#define LL long long
using namespace std;
int l,t,o;
inline void m_swap(int &a, int &b){
    int t=a;
    a=b;
    b=t;
}
struct nod{
    int l, r;
    LL val, lazy;
} tre[MAXN*4];
void push_up(int x){
    tre[x].val = tre[sl].val|tre[sr].val;
}
void built(int x, int l, int r){
    tre[x].l=l,tre[x].r=r;
    if(l==r){
        tre[x].val=1;
        return;
    }
    int mid=(l+r)>>1;
    built(sl, l, mid);
    built(sr, mid+1, r);
    push_up(x);
}
void push_down(int x){
    if(tre[x].lazy==0) return;
    tre[sl].val=tre[sr].val=tre[x].lazy;
    tre[sl].lazy=tre[sr].lazy=tre[x].lazy;
    tre[x].lazy=0;
}
void change(int x, int l, int r, LL val){
    if(l<=tre[x].l&&tre[x].r<=r){
        tre[x].val=val;
        tre[x].lazy=val;
        return;
    }
    push_down(x);
    int mid=(tre[x].l+tre[x].r)>>1;
    if(l<=mid) change(sl, l, r, val);
    if(r>mid) change(sr, l, r, val);
    push_up(x);
}
LL query(int x, int l, int r){
    if(l<=tre[x].l&&tre[x].r<=r)
        return tre[x].val;
    push_down(x);
    int mid=(tre[x].l+tre[x].r)>>1;
    LL ans=0;
    if(l<=mid) ans|=query(sl, l, r);
    if(r>mid) ans|=query(sr, l, r);
    return ans;
}
int main()
{
    ios::sync_with_stdio(0);
    cin>>l>>t>>o;
    built(1, 1, l);
    while(o--){
        char opt;cin>>opt;
        if(opt=='C'){
            int a,b,c;cin>>a>>b>>c;
            if(a>b) m_swap(a,b);
            LL val=(1<<(c-1));
            change(1, a, b, val);
        }else{
            int a,b;cin>>a>>b;
            if(a>b) m_swap(a,b);
            LL res=query(1, a, b);
            int ans=0;
            for(int i=0;i<=t-1;++i)
                if((1<<i)&res) ans++;
            cout<<ans<<endl;
        }
    }
    return 0;
}
posted @ 2019-06-05 11:08  Santiego  阅读(263)  评论(0编辑  收藏  举报