【题意】给了每一线段的颜色,存在颜色覆盖,求表面上看能看到的颜色种类和各种颜色的段数

【分析&解题思路】延迟标记的思想,在儿子结点更新到之前,要把父亲节点的标记传到儿子结点。

【AC代码】

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 8005;
int vis[maxn<<2],ans[maxn];
struct node{
    int l,r,col;
}Tree[maxn<<2];
void Push_Down(int rt){
    if(Tree[rt].col!=-1){
        Tree[rt<<1].col=Tree[rt<<1|1].col=Tree[rt].col;
        Tree[rt].col=-1;
    }
}
void Build(int l,int r,int rt){
    Tree[rt].l=l,Tree[rt].r=r,Tree[rt].col=-1;
    if(l==r) return ;
    int mid=(l+r)>>1;
    Build(l,mid,rt<<1);
    Build(mid+1,r,rt<<1|1);
}
void Update(int L,int R,int c,int rt){
    if(L<=Tree[rt].l&&Tree[rt].r<=R){
        Tree[rt].col=c;
        return ;
    }
    else{
        Push_Down(rt);
        int mid=(Tree[rt].l+Tree[rt].r)>>1;
        if(L<=mid) Update(L,R,c,rt<<1);
        if(mid<R)  Update(L,R,c,rt<<1|1);
    }
}
void query_ans(int rt){
    if(Tree[rt].col>=0){
        for(int i=Tree[rt].l; i<=Tree[rt].r; i++) vis[i]=Tree[rt].col;
        return ;
    }
    if(Tree[rt].l==Tree[rt].r) return ;
    if(Tree[rt].col!=-1)       return ;
    query_ans(rt<<1);
    query_ans(rt<<1|1);
}
int main(){
    int n,a,b,c;
    while(~scanf("%d",&n)){
        Build(1,maxn,1);
        for(int i=0; i<n; i++){
            scanf("%d%d%d",&a,&b,&c);
            if(a>=b) continue;
            Update(a+1,b,c,1);
        }
        memset(ans,0,sizeof(ans));
        memset(vis,-1,sizeof(vis));
        query_ans(1);
        int i=1;
        while(i<maxn){
            int color=vis[i],j=i+1;
            if(color==-1){i++;continue;}
            while(vis[j]!=-1&&vis[j]==color&&j<maxn) j++;
            ++ans[color];
            i=j;
        }
        for(int i=0; i<maxn; i++){
            if(ans[i]){
                printf("%d %d\n",i,ans[i]);
            }
        }
        printf("\n");
    }
    return 0;
}