题目链接点击打开链接
题意:对一条直线成段染色,求最后能看到的颜色以及每一种颜色的不连续段数。
思路:本题有两个难点。
第一:线段树的编号都是点,比如更新1-3更新1 2 3这三个点。二对于本题,更新1-3则表示更新1-2 和2-3这两个单位1的区间。解决的方法是把第二种更新方式改为第一种。只需要左端点值加1即可。
第二,如何统计同颜色不连续区间个数。如果每遇到一个颜色就对该颜色加1的话,很显然递归时相邻区间交界处如果颜色相同,会被重复计算。通过分析query函数发现,线段树采取类似后序遍历的方法。访问完一个区间后,接下来访问的区间必然是其右边相邻的区间。那么我们对当前区间颜色进行记录,判断访问下一个区间时判断两种颜色是否相等即可。
AC代码
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<algorithm>
#include<iostream>
#include<string>
#pragma comment(linker, "/STACK:102400000,102400000")
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef long long ll;
using namespace std;
const ll maxn=1005;
const int N = 100000;
int col[N<<2],lazy[N<<2],sum[N],pre; ///pre 存前面一段的颜色
void PushUp(int rt)
{
if(col[rt<<1]==col[rt<<1|1]) col[rt] = col[rt<<1];
else col[rt] = -1;
}
void PushDown(int rt)
{
if(lazy[rt])
{
lazy[rt<<1] = lazy[rt<<1|1] = lazy[rt];
col[rt<<1] = col[rt<<1|1] = lazy[rt];
lazy[rt] = 0;
}
}
void build(int l,int r,int rt)
{
lazy[rt] = 0;
if(l==r)
{
col[rt] = 0;
return ;
}
int m = (l+r)>>1;
build(lson);
build(rson);
PushUp(rt);
}
void update(int L,int R,int c,int l,int r,int rt)
{
if(L<=l && r<=R)
{
col[rt] = c;
lazy[rt] = c;
return ;
}
int m = (l+r)>>1;
PushDown(rt);
if(L<=m) update(L,R,c,lson);
if(m<R) update(L,R,c,rson);
PushUp(rt);
}
void query(int l,int r,int rt = 1)
{
if(col[rt]!=-1)
{
if(col[rt]!=pre) sum[col[rt]] ++ ;
pre = col[rt] ;
return ;
}
PushDown(rt);
int m = (l+r)>>1;
query(lson);
query(rson);
}
int main()
{
int T,n,q,L,R,col,cs = 1,mx;
while(~scanf("%d",&q))
{
memset(sum,0,sizeof(sum));
mx = 0,pre = - 2;
build(1,8000,1);
while(q--)
{
scanf("%d%d%d",&L,&R,&col);
L++;
col ++ ;
update(L,R,col,1,8000,1);
mx = max(mx,col);
}
query(1,8000,1);
for(int i=1;i<=mx;i++)
{
if(sum[i]) printf("%d %d\n",i-1,sum[i]);
}
puts("");
}
return 0;
}