题目链接: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;
}