poj 2777 Count Color

/*
poj4 2777 Count Color
题意: 给你一个长度为L(L<=100000)的线段,还有t种颜色(t<30),整条线段初始化为颜色 1,有两种操作:
C a b c : 将从a到b的线段涂上c颜色;
P a b: 查询从a到b的线段上有多少种颜色。

颜色的表示方法: 颜色的种类不多(2<<T在int 范围内),因此使用二进制来存储颜色的信息,
右起第n位上有 1 则表示是颜色n。具体说来,就是用1表示颜色1,10表示颜色2,100表示颜色3,
1001 = 9表示 1 , 4 这2种颜色 ……依次类推,这样表示有一种好处,涂颜色相当于进行 或 运算,
要统计出有多少种不同颜色,只需找出这个数的二进制表示里有几个 1 , 可以这样统计 1 的个数:
int calculate(int p) //计算出p值所含的不同颜色种类数
{
int s=0;
while(p>0)
{
s++;
p-=(p&(-p)); //每次都把右边起的第1个 1 变成 0
}
return s;
}
比如10100, 10100&(-10100)=100, 10100-100=10000
10000&(-10000)=10000, 10000-10000=0 至此循环终止, s=2, 表示有两个 1
采用位运算代替vis[]数组来表示哪些颜色存在或不存在,这样既省空间也省时间

*/



#include <iostream> // 线段树+位运算
using namespace std;

struct node
{
int l,r;
int color; //数值color的二进制表示 就是区间[l,r]内有哪些颜色
}tree[300000];


void build(int n,int s,int t)
{
tree[n].l=s;
tree[n].r=t;
tree[n].color=1; //整条线段初始化为颜色 1
if(s!=t)

{
int mid=(s+t)/2;
build(2*n,s,mid);
build(2*n+1,mid+1,t);
}
}
int calculate(int p) //计算出p值所含的不同颜色种类数
{

int s=0;
while(p>0)
{
s++;
p-=(p&(-p));
}
return s;
}

int c,ans;
void modify(int n,int a,int b)
{
if(calculate(tree[n].color)==1&&tree[n].l<tree[n].r) //如果是叶子节点,则不能更新左右子树,所以tree[n].l<tree[n].r
{

tree[2*n].color=tree[2*n+1].color=tree[n].color;
//更新孩子区间的颜色值,如果该区间的不同颜色数量不是1的话,则它的孩子区间也必已更新了
}



//因为在插入一个区间时,当插入区间等于当前区间时,当前区间的颜色就剩下一种,
//当前区间的孩子区间也全都一样,不需要一直更新到叶子节点
//等到重新插入另一个区间时再来更新孩子区间不同颜色数量,如果一直更新到叶子节点,则会TLE
if( tree[n].l==a && tree[n].r==b ) //插入区间等于当前区间
tree[n].color=c;

else
{
if(b<=tree[2*n].r)
modify(2*n,a,b);
else if(a>=tree[2*n+1].l)
modify(2*n+1,a,b);
else
{
int mid=(tree[n].l+tree[n].r)>>1;
modify(2*n,a,mid);
modify(2*n+1,mid+1,b);
}
tree[n].color = tree[2*n].color | tree[2*n+1].color ; // 位运算
}

}
void query(int n,int a,int b)
{
if(calculate(tree[n].color)==1&&tree[n].l<tree[n].r) //同上
{

tree[2*n].color=tree[2*n+1].color=tree[n].color;
}
if(a==tree[n].l&&b==tree[n].r)
ans = ans | tree[n].color ; // 位运算
else

{
if(b<=tree[2*n].r)
query(2*n,a,b);
else if(a>=tree[2*n+1].l)
query(2*n+1,a,b);
else
{
int mid=(tree[n].l+tree[n].r)>>1;
query(2*n,a,mid);
query(2*n+1,mid+1,b);
}
}
}
int main()
{
int L,T,q,a,b;
char ch;
cin>>L>>T>>q;
build(1,1,L);
while(q--)
{
cin>>ch;
if(ch=='C')
{
scanf("%d%d%d",&a,&b,&c);
if(a>b)
swap(a,b);
c=1<<(c-1); //二进制下右起第 c 位是 1
modify(1,a,b);

}
else
{
ans=0;
scanf("%d%d",&a,&b);
if(a>b)
swap(a,b);
query(1,a,b);
printf("%d\n", calculate( ans ) );
}
}
return 0;
}

posted on 2011-07-22 15:07  sysu_mjc  阅读(133)  评论(0编辑  收藏  举报

导航