P1558 色板游戏 状压线段树
P1558 色板游戏 状压线段树
每次不同颜色覆盖一段区间,每次询问一段区间有多少种颜色
因为颜色数\(T\)很小,使用二进制表示状态当前区间有那些颜色,二进制第\(i\)位表示此区间是否含有\(i\)这种颜色,线段树合并信息时左右儿子信息或一下就好了。
scanf
读入char
炸了我好久,最后换成cin
就AC了
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;
}