POJ 2777 - Count Color(线段树区间更新+状态压缩)
题目链接 https://cn.vjudge.net/problem/POJ-2777
【题意】
有一个长度为 的区间 ,有 种颜色可以涂,有 次操作,操作分两种
把区间 涂成第 种颜色
查询区间 有多少种不同的颜色
初始全部为第 种颜色()
【思路】
因为颜色种类比较少,所以可以用二进制来表示某个区间的颜色集合,合并时用按位或运算,用lazy标记区间更新,查询结果中二进制里1的个数就是答案
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define node tree[id]
#define lson tree[id<<1]
#define rson tree[id<<1|1]
using namespace std;
const int maxn=100005;
struct Tree{
int left,right;
int col,lazy;
}tree[maxn<<2];
int n,m,q;
void pushup(int id){node.col=lson.col|rson.col;}
void pushdown(int id){
if(node.lazy && node.left!=node.right){
lson.lazy=node.lazy;
lson.col=(1<<(node.lazy-1));
rson.lazy=node.lazy;
rson.col=(1<<(node.lazy-1));
node.lazy=0;
}
}
void build(int id,int le,int ri){
node.left=le;
node.right=ri;
node.lazy=0;
if(le==ri){
node.col=1;
return;
}
int mid=(le+ri)>>1;
build(id<<1,le,mid);
build(id<<1|1,mid+1,ri);
pushup(id);
}
void update(int id,int le,int ri,int val){
if(node.left==le && node.right==ri){
node.col=(1<<(val-1));
node.lazy=val;
return;
}
pushdown(id);
int mid=(node.left+node.right)>>1;
if(ri<=mid) update(id<<1,le,ri,val);
else if(le>mid) update(id<<1|1,le,ri,val);
else{
update(id<<1,le,mid,val);
update(id<<1|1,mid+1,ri,val);
}
pushup(id);
}
int query(int id,int le,int ri){
if(node.left==le && node.right==ri){
return node.col;
}
pushdown(id);
int mid=(node.left+node.right)>>1;
if(ri<=mid) return query(id<<1,le,ri);
else if(le>mid) return query(id<<1|1,le,ri);
else{
return query(id<<1,le,mid)|query(id<<1|1,mid+1,ri);
}
}
int main(){
while(scanf("%d%d%d",&n,&m,&q)==3){
build(1,1,n);
while(q--){
char op[2];
scanf("%s",op);
if(op[0]=='C'){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
if(a>b) swap(a,b);
update(1,a,b,c);
}
else{
int a,b;
scanf("%d%d",&a,&b);
if(a>b) swap(a,b);
int ans=query(1,a,b);
printf("%d\n",__builtin_popcount(ans));
}
}
}
return 0;
}