题目链接:http://poj.org/problem?id=2777
经典的线段树问题
1)建树,树节点有三个域,分别为左右端点l,r与代表颜色的c,当c等于0的时候表示被多种颜色覆盖了.
2)更新,如果在查找的过程中遇到当前区间的颜色大于0,也就是说这个区间已经被完全染色过,那么就把这个区间
的颜色值往下传递,然后把这个区间的颜色值c赋值为0,继续往下查找,有三种情况:左子树,右子树,或者左右子
树混合的直到当前区间的跟所要更新的区间一致,停止往下更新!进行染色,也就是把c值附给他,还有一种情况就
是:当前区间的c值大于0并且等于我所要染色的颜色值,这样也可以停止往下更新!
3)计数,在往下计数的时候,如果遇到c值大于0的直接把他在color[]表里的映射赋值为1,这样防止重复计数!
如果c==0;就继续往下计数.
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
#define N 100010
struct node
{
int l,r,c;
}line[4*N];
int color[40];
void create(int k,int x,int y)
{
line[k].l=x;line[k].r=y;line[k].c=1;
if(x==y) return;
int mid=(x+y)>>1;
create(k<<1,x,mid);
create(k<<1|1,mid+1,y);
}
void change(int k,int x,int y,int val)
{
if(line[k].c==val) return;
if(x<=line[k].l&&line[k].r<=y)
{
line[k].c=val;
return;
}
if(line[k].c!=0)
{
line[k<<1].c=line[k<<1|1].c=line[k].c;
line[k].c=0;
}
int mid=(line[k].l+line[k].r)>>1;
if(x>mid)
change(k<<1|1,x,y,val);
else if(y<=mid)
change(k<<1,x,y,val);
else
{
change(k<<1,x,mid,val);
change(k<<1|1,mid+1,y,val);
}
}
void visit(int k,int x,int y)
{
if(line[k].c>0)
{
color[line[k].c]=1;
return;
}
int mid=(line[k].l+line[k].r)>>1;
if(x>mid)
visit(k<<1|1,x,y);
else if(y<=mid)
visit(k<<1,x,y);
else
{
visit(k<<1,x,mid);
visit(k<<1|1,mid+1,y);
}
}
int main()
{
int L,T,O,i,j,a,b,c,mt;
char s;
while(scanf("%d%d%d",&L,&T,&O)!=EOF)
{
create(1,1,L);
for(i=1;i<=O;i++)
{
getchar();
scanf("%c",&s);
if(s=='C')
{
scanf("%d%d%d",&a,&b,&c);
change(1,a,b,c);
}
if(s=='P')
{
scanf("%d%d",&a,&b);
memset(color,0,sizeof(color));
visit(1,a,b);mt=0;
for(j=1;j<=T;j++)
if(color[j]) mt++;
printf("%d\n",mt);
}
}
}
return 0;
}