先来谈谈lazy思想。做了这么多的线段树,应该总结一下,lazy是一个很经典的思
pku2777 线段树(染色问题)想。所谓lazy,就是懒惰,每次不想做太多,只要插入的区间完全覆盖了当前结点所管
pku2777 线段树(染色问题)理的区间就不再往下做了,在当前结点上打上一个lazy标记,然后直接返回。下次如果
pku2777 线段树(染色问题)遇到当前结点有lazy标记的话,直接传递给两个儿子,自己的标记清空。这样做肯定是
pku2777 线段树(染色问题)正确的。我们以染色为例,可以这样想,如果当前结点和它的子孙都有lazy标记的话,
pku2777 线段树(染色问题)必定是子孙的先标记,因为如果是自己先标记,那么在访问子孙的时候,必定会将自己
pku2777 线段树(染色问题)的标记下传给儿子,而自己的标记必定会清空,那么lazy标记也就不存在了。所以可以
pku2777 线段树(染色问题)肯定,当前的lazy标记必定覆盖了子孙的,所以直接下传即可,不需要做任何判断。当
pku2777 线段树(染色问题)然,这是染色问题,是直接赋值的,如果像pku 3468那样,每次是区间加和,则传递标
pku2777 线段树(染色问题)记的时候不能简单的赋值,必须累加,这是显而易见的。

 一看到数据量就可以首先确定是线段树了,经典的区间染色问题,涉及到区间的
pku2777 线段树(染色问题)更新和询问,和pku 3468 类似,巧妙运用lazy思想。就是每次更新区间段的时候延迟
pku2777 线段树(染色问题)更新,只是在完全覆盖的区间打上一个lazy标记。这题的询问是求区间段中不同颜色的
pku2777 线段树(染色问题)数量,因为颜色数不多只有30种,可以巧妙运用二进制位运算,用一个int就可以表示
pku2777 线段树(染色问题)当前区间段的颜色情况。比如1001表示有两种颜色,如果左子树的当前颜色情况是101
pku2777 线段树(染色问题),而右子树的颜色情况是011,那么父亲的颜色情况就是两者的位或,这样就可以避免
pku2777 线段树(染色问题)掉重复的情况。

#include<stdio.h>
#define N 100010
struct node{
int l,r,c;
}p[N
*3];
int flag,count;
void bulid(int k,int s,int t)
{
int kl,kr,mid;
p[k].r
=t;p[k].l=s;
p[k].c
=1;
if(t==s)return ;

mid
=(s+t)>>1;kl=k<<1;kr=kl+1;
bulid(kl,s,mid);
bulid(kr,mid
+1,t);

}
void updata(int k,int s,int t,int v)
{
int kr,kl,mid;
if(p[k].c==v)
return ;
if(s<=p[k].l&&t>=p[k].r)
p[k].c
=v;
else {
mid
=(p[k].r+p[k].l)>>1;kl=k<<1;kr=kl+1;
if(p[k].c!=-1)
{
p[kr].c
=p[kl].c=p[k].c;
p[k].c
=-1;
}
if(s<=mid)updata(kl,s,t,v);
if(t>mid)updata(kr,s,t,v);
}
}
void query(int k,int s,int t)
{
int kr,kl,mid;
if(p[k].c>0)
{
int t=p[k].c;
if((flag&(1<<t))==0)//由于颜色只有30种,所以可以用位运算来标记状态
{ //注意这里的移位操作,flag的32个位上的1和0分别表示该位的位置代表的
// 颜色是否存在过,先将1左移t个位,则只有第t+1个位上的数字为1,其余为0,
count
++; // 当与flag进行位与运算等于0时,则表示所对应的颜色没出现过
flag
|=1<<t; //同样的,若出现过,则用flag在该位上标记一下
}
return ;
}
mid
=(p[k].r+p[k].l)>>1;kl=k<<1;kr=kl+1;
if(s<=mid) query(kl,s,t);
if(t>mid) query(kr,s,t);
}
int main()
{
int n,m,a,b,x,t;
char ch[2];
while(scanf("%d %d %d",&n,&t,&m)!=EOF)
{
bulid(
1,1,n);
while(m--)
{
scanf(
"%s",ch);
if(ch[0]=='C')
{
scanf(
"%d %d %d",&a,&b,&x);
if(a>b) { t=a;a=b;b=t;}
updata(
1,a,b,x);
}
else {
flag
=count=0;
scanf(
"%d %d",&a,&b);
if(a>b){t=a;a=b;b=t;}
query(
1,a,b);
printf(
"%d\n",count);
}
}
}
return 0;
}

相关文章: