Zju1610 Count the Colors

题面:

画一些颜色段在一行上,一些较早的颜色就会被后来的颜色覆盖了。
你的任务就是要数出你随后能看到的不同颜色的段的数目。

Input:

每组测试数据第一行只有一个整数n, 1 <= n <= 8000,等于填色的次数
接下来的n行每行有三个非负整数,他们之间用一个空格分开。
x1 x2 c
x1和x2表示填色段最左边的点和最右边的点, c表示填进的颜色。
所有数字都是在[0..8000]这个范围里的整数。
输入有多组测试数据,最后以文件结束符为结束。

Output:

输出的每一行都是最后能看到的颜色的数字,还有这种颜色的段数。
如果这种颜色最后不能见到,就不要打印出来。
每组数据后面跟一个空行。

Solution:

说实话,这道题十分的傻逼,我一开始想的时候一直没想出来,一看题解,豁然开朗:原来还可以这么暴力啊。。。
线段树,tree数组记录当前区间是否颜色一致,若颜色一致,则等于那个颜色,否则等于-1
那么叶子节点的tree记录的显然是自己的颜色,所以最后再线段树查找单点颜色就行了
把颜色都记录下来后,O(N)扫一遍就行了

Code:

#include<bits/stdc++.h>
#define N 8001
#define ls (q<<1)
#define rs (q<<1|1)
using namespace std;
int n,cl,cc,tree[N*5],col[N],ans[N];
inline int read(){ 
    int x=0,f=1;char ch=getchar(); 
    while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();} 
    while(isdigit(ch)){x=x*10+ch-48;ch=getchar();} 
    return x*f; 
}
void pushdown(int q){
    if(tree[q]!=-1)tree[ls]=tree[rs]=tree[q];
    tree[q]=-1;
}
void change(int l,int r,int q,int L,int R,int v){
    if(tree[q]==v)return ;
    if(l>=L&&r<=R){
        tree[q]=v;
        return ;
    }
    pushdown(q);
    int mid=(l+r)>>1;
    if(mid>=L)change(l,mid,ls,L,R,v);
    if(mid<R)change(mid+1,r,rs,L,R,v);
}
int query(int l,int r,int q,int x){
    if(l==r)return tree[q];
    int mid=(l+r)>>1;
    pushdown(q);
    if(mid>=x)return query(l,mid,ls,x);
    if(mid<x)return query(mid+1,r,rs,x);
}
int main(){
    while((scanf("%d",&n))!=EOF){
        memset(tree,255,sizeof(tree));
        memset(col,255,sizeof(col));
        memset(ans,0,sizeof(ans));
        for(int i=1;i<=n;i++){
            int l=read(),r=read(),v=read();
            change(0,N,1,l,r-1,v);//因为是区间长度,所以r要减一
        }
        int pre=-1;
        for(int i=0;i<=N;i++){
            int now=query(0,N,1,i);
            if(now!=-1&&now!=pre)ans[now]++;
            pre=now;
        }
        for(int i=0;i<=N;i++)
        if(ans[i])printf("%d %d
",i,ans[i]);
        puts("");
    }
    return 0; 
}
原文地址:https://www.cnblogs.com/NLDQY/p/10085173.html