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;
}