您的位置:首页 > 产品设计 > UI/UE

pku 2777 Count Color(线段树变形)

2009-07-26 07:19 411 查看
 

因为操作次数很多,所以修改操作应该选用O(logN)的方式,线段树成为最佳选择。
这题有两个注意的地方,一是因为线段以segment为划分单位,所以右子树的left比左子树的right要大1。二是给线段树结点增加一个color域,当整个线段为纯色时,color=颜色代号,当线段内有多种颜色是,color=-1。这里当父节点涂色时,说明其所有子节点的颜色都需要更新。但因为考虑到效率问题,不可能去这样操作,这样就给insert操作和cal操作带来了一点改变,需要特别注意(通常线段树都是子节点控制父节点,这次是父节点控制子节点)。
 
#include <iostream>
using namespace std;
#define MAXLENGTH 100005
struct node
{
int left,right,color;
}my_tree[MAXLENGTH*10];
bool used[30+5];
void swap(int a,int b)
{
int temp=a;
a=b;
b=temp;
}
void build(int a,int b,int i)
{
my_tree[i].left=a;
my_tree[i].right=b;
if(b-a)//当segment大于2时,就继续往下划分
{
build(a,(a+b)/2,i*2);
build((a+b)/2+1,b,i*2+1);
}
}
void insert(int a,int b,int c,int i)
{
if(my_tree[i].left==a&&my_tree[i].right==b)
{
my_tree[i].color=c;
}
else
{
if(my_tree[i].color>0) my_tree[i*2].color=my_tree[i*2+1].color=my_tree[i].color,my_tree[i].color=-1;//极为关键
int mid=(my_tree[i].left+my_tree[i].right)/2;
if(b<=mid)
{
insert(a,b,c,2*i);
}
else if(a>mid)
{
insert(a,b,c,2*i+1);
}
else
{
insert(a,mid,c,i*2);
insert(mid+1,b,c,i*2+1);
}

}
}
void cal(int a,int b,int i)
{
if(my_tree[i].color>0) //正确的操作下,总是有left<=a<=b<=right,所以只要线段颜色确定,立即返回
{
used[my_tree[i].color]=true;
}
else
{
int mid=(my_tree[i].left+my_tree[i].right)/2;
if(b<=mid) cal(a,b,2*i);
else if(a>mid) cal(a,b,2*i+1);
else
{
cal(a,mid,i*2);
cal(mid+1,b,i*2+1);
}
}
}
int main()
{
int L,T,O;
char flag;
int A,B,C,ans;
scanf("%d%d%d",&L,&T,&O);
build(1,L,1);
my_tree[1].color=1;
for(int i=0;i<O;i++)
{
scanf(" %c",&flag);
if(flag=='C')
{
scanf("%d%d%d",&A,&B,&C);
if(A>B) swap(A,B);
insert(A,B,C,1);
}
else
{
scanf("%d%d",&A,&B);
if(A>B) swap(A,B);
memset(used,0,sizeof(used));
cal(A,B,1);
ans=0;
for(int j=1;j<=T;j++)
{
if(used[j]) ans++;
}
printf("%d/n",ans);
}
}
return 0;
}
 
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  tree insert build c struct