Count the Colors ZOJ - 1610

原题链接
考察:线段树
思路:
  还是线段树染色问题..
  但还是和上一题有点区别,单以样例1来说:
5
0 4 4 ---> 1 5 5
0 3 1 ---> 1 4 2
3 4 2 ---> 4 5 3
0 2 2 ---> 1 3 3
0 2 3 ---> 1 3 4
  颜色与我们定义线段树区间颜色表示相冲突,所以进行坐标偏移.注意到区间(3,4).这中间按理解应该还是1色.但是如果我们以以前定义的线段树进行维护就会发现(3,4)区间的1色会被记为-1.其中[3,3]是4色,[4,4]是3色.这样中间的1色就会被忽略.
  所以需要修改线段树维护区间[l,r]的定义.以前我们染色是把[L,R+1)这段区间全部染色.这里r--就可以染色[l,R).(原本是偏移,--相当于不动)

Code:

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 8010;
int n,R[N],cnt[N];
struct Node{
	int l,r,c;
}tr[N<<2];
void push_up(int u)
{
	int l = tr[u<<1].c,r = tr[u<<1|1].c;
	if(l==r) tr[u].c = l;
	else tr[u].c = -1;
}
void build(int u,int l,int r)
{
	tr[u].l = l,tr[u].r = r;
	if(l==r) {tr[u].c = 0;return;}
	int mid = l+r>>1;
	build(u<<1,l,mid),build(u<<1|1,mid+1,r);
	push_up(u);
}
void push_down(int u)
{
    tr[u<<1].c = tr[u<<1|1].c = tr[u].c;
}
void modify(int u,int l,int r,int x)
{
	if(tr[u].l>=l&&tr[u].r<=r) { tr[u].c = x;return; }
	if(tr[u].c!=-1) push_down(u);
	int mid = tr[u].l+tr[u].r>>1;
	if(l<=mid) modify(u<<1,l,r,x);
	if(mid<r) modify(u<<1|1,l,r,x);
	push_up(u);
}
void query(int u,int l,int r)
{
	if(tr[u].l>=l&&tr[u].r<=r&&tr[u].c!=-1)
	{
		if(R[tr[u].c]+1!=tr[u].l) cnt[tr[u].c]++;
		R[tr[u].c] = tr[u].r;
		return;
	}
	if(tr[u].c!=-1) push_down(u);
	int mid = tr[u].l+tr[u].r>>1;
	if(l<=mid) query(u<<1,l,r);
	if(mid<r) query(u<<1|1,mid+1,r);
} 
int main()
{
	while(scanf("%d",&n)!=EOF)
	{
		build(1,1,8001);
		memset(R,-0x3f,sizeof R);
		memset(cnt,0,sizeof cnt);
		while(n--)
		{
			int l,r,c;
			scanf("%d%d%d",&l,&r,&c);
			l++;
			if(l<=r) modify(1,l,r,c+1);
		}
		query(1,1,8001);
		for(int i=1;i<=8001;i++)
		  if(cnt[i]) printf("%d %d\n",i-1,cnt[i]);
		printf("\n");
	}
	return 0;
}
posted @ 2021-05-20 13:21  acmloser  阅读(37)  评论(0编辑  收藏  举报