您的位置:首页 > 其它

ZOJ 1610 Count the Colors 线段树区间染色问题

2015-04-30 12:47 429 查看
题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=66989#problem/F

题意:给一个区间范围,然后逐步给某些区间染色,最后问能各种能看见的颜色的块数。典型的线段树染色问题,看了别人的代码不太能理解。但是想到了一个不错的思路。

解题思路:我们可以这样想,显然每条线段最后的颜色都由改线段最后一次的染色决定,如果我们把每一次染色都标记一个步数,显然每条线段的最后颜色就由其上面的区间中所包含的最大步数所决定,这样就好想多了,我们每一次染色就对目标区间插入一个步数,顺便记录下该步数所用的颜色,最后用O(n)的时间求出每个叶子的最后步数和颜色即可。

由于线段树最后的叶子一般都是一个点,而本题最小的单位是一条线段而不是一个点,所以我们把每一条线段看成一个点,建立线段树。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 8010
#define LL long long

using namespace std;
struct node{
int l,r,w;//区间的左右端点,和该区间的最后一个染色步数
}T[maxn*3];

int n,col[maxn],A[maxn],cnt[maxn];

void build(int L,int R,int o){
T[o].l=L;T[o].r=R;T[o].w=0;
if(L==R) return;
build(L,(L+R)/2,o*2);
build((L+R)/2+1,R,o*2+1);
}

void add(int L,int R,int step,int o){
if(T[o].l>=L && T[o].r<=R) {T[o].w=step;return;}
if(T[o].l==T[o].r) return;
if(L>=T[o*2+1].l) add(L,R,step,o*2+1);
else if(R<=T[o*2].r) add(L,R,step,o*2);
else{
add(L,T[o*2].r,step,o*2);
add(T[o*2+1].l,R,step,o*2+1);
}
}

void dfs(int o,int Max){//dfs遍历线段树并求出叶子的颜色
Max=max(Max,T[o].w);
if(T[o].l==T[o].r) {A[T[o].l]=col[Max];return;}
dfs(o*2,Max);
dfs(o*2+1,Max);
}

void disp(){
int t=-1;
memset(cnt,0,sizeof(cnt));
for(int i=0;i<=8000;i++){//处理相连颜色的情况
if(A[i]==-1 || A[i]==t){t=A[i];continue;}
t=A[i];
cnt[t]++;
}
for(int i=0;i<=8000;i++) if(cnt[i])
printf("%d %d\n",i,cnt[i]);
printf("\n");
}

int main(){
//freopen("in.txt","r",stdin);
while(cin>>n){
build(1,8000,1);//把每一线段看成一个端点,所以从1开始
int a,b,c;
col[0]=-1;
for(int i=1;i<=n;i++){
scanf("%d %d %d",&a,&b,&c);
col[i]=c;//记录第i个输入的颜色
add(a+1,b,i,1);//这里以单位线段为一个点,插入一个步数
}
memset(A,-1,sizeof(A));//-1表色没有染过色
dfs(1,0);//更新每个叶子的最后步数和颜色
disp();//输出答案
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: