zoj 1610 Count the Colors(线段树)(成段更新染色)

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1610

题意:对一段区间进行涂色,问最后每一种可见的颜色共占多少个不连续的区间。

方法:线段树+延迟标志

思路:这到题目的关键一点是区间不能取闭区间,根据题意,为了方便可以取左开右闭,而且要搞明白涂色的是区间而不是点,因此根据线段树不能一步得到结果,我们可以利用线段树的延时更新策略,即一个节点表示一段区间,如果这段区间是纯色的,那么会在这个点上进行标记,于是就不需要对其子区间进行图色了,除非下次图色的时候发生覆盖,才需要继续向下更新,最终线段树可以以较小的代价得到最终的色彩分布,然后,我们再去线性扫描一遍这个分布,就可以得到每种颜色的分布,将颜色值作为数组的下标,这样在扫描完成后得到的数据就是按照颜色值的变化的。

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int  maxn = 8010;
int x[maxn<<2];
int col[maxn<<2];//类似于延迟标记  只有查询或者更新到该点时才往下传递
bool vis[maxn];
int cnt[maxn];
void pushdown(int rt)
{
	if(col[rt]!=-1)
	{
		col[rt<<1]=col[rt<<1|1]=col[rt];
		col[rt]=-1;
	}
}
void update(int L,int R,int c,int l,int r,int rt)
{
	if(L<=l&&r<=R)
	{
		col[rt]=c;
		return ;
	}
	if(col[rt]==c)return ;
	pushdown(rt);
	int m=(r+l)>>1;
	if(L<=m)update(L,R,c,lson);
	if(R>m)update(L,R,c,rson);
}
void query(int l,int r,int rt)
{
	if(col[rt]!=-1)
	{
		for(int i=l;i<=r;i++)
			x[i]=col[rt];
		return ;
	}
	if(l==r||col[rt]!=-1)return ;
	int m = (l + r) >> 1;
	query(lson);
	query(rson);
}
int main()
{
	int n;
	while(~scanf("%d",&n))
	{
		memset(col,-1,sizeof col);
		memset(x,-1,sizeof x);
		int a,b,c;
		while(n--)
		{
			scanf("%d%d%d",&a,&b,&c);
			update(a+1,b,c,1,maxn,1);//左开右闭区间
		}
		query(1,maxn,1);

		memset(cnt,0,sizeof cnt);
		for(int i=0;i<maxn;)
		{
			while(x[i]==-1&&i<maxn)
				i++;
			if(i>maxn)break;
			int ans=x[i];
			cnt[ans]++;
			while(i<maxn&&x[i]==ans)
				i++;
		}

		for(int i=0;i<maxn;i++)
		{
			if(cnt[i]!=0)
				printf("%d %d\n",i,cnt[i]);
		}
		printf("\n");
	}
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值