ZOJ 1610Count the Colors 线段树_区间更新

来源:互联网 发布:360电脑软件管家 编辑:程序博客网 时间:2024/04/27 14:49

Count the Colors
Time Limit: 2 Seconds      Memory Limit: 65536 KB
Painting some colored segments on a line, some previously painted segments may be covered by some the subsequent ones.
Your task is counting the segments of different colors you can see at last.


Input

The first line of each data set contains exactly one integer n, 1 <= n <= 8000, equal to the number of colored segments.

Each of the following n lines consists of exactly 3 nonnegative integers separated by single spaces:

x1 x2 c

x1 and x2 indicate the left endpoint and right endpoint of the segment, c indicates the color of the segment.

All the numbers are in the range [0, 8000], and they are all integers.

Input may contain several data set, process to the end of file.


Output

Each line of the output should contain a color index that can be seen from the top, following the count of the segments of this color, they should be printed according

to the color index.

If some color can't be seen, you shouldn't print it.

Print a blank line after every dataset.


Sample Input

5
0 4 4
0 3 1
3 4 2
0 2 2
0 2 3
4
0 1 1
3 4 1
1 3 2
1 3 1
6
0 1 0
1 2 1
2 3 1
1 2 0
2 3 0
1 2 1


Sample Output

1 1
2 1
3 1

1 1

0 2
1 1

 

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define inf -0x3f3f3f3f
#define FOR(a,b) for(int i =  a ; i < b ; i++)
#define mem0(a) memset(a,0,sizeof(a))
const int maxn =8000+10;
struct node {
    int l,r;
    int cor;//颜色标记,-1表示未涂色,-2表示混合
}a[maxn<<2];
int num[maxn]={0},last=-1;
void build(int l,int r,int cur){
    a[cur].l = l ;
    a[cur].r = r;
    a[cur].cor = -1;//初始建立树都未标记
    if(l + 1 == r) return ;//更新到子叶时返回
    int mid = (l + r)>>1;
    build(l,mid,cur<<1);//建立左子树
    build(mid,r,cur<<1|1);//建立右子树
}
void insert(int l,int r,int v,int cur){
    int mid ;
    if(a[cur].l == l && a[cur].r == r|| a[cur].cor== v ){
        a[cur].cor = v;return ;//插入的线段匹配则此条线段的颜色改变
    }//涂色区间正好匹配或颜色相同
    if(a[cur].cor >= 0){
        //如果插入区间有颜色, 则要在插入区间内重新覆盖
        a[cur<<1].cor = a[cur].cor;
        a[cur<<1|1].cor = a[cur].cor;
    }
    a[cur].cor = -2 ;
    mid = (a[cur].l + a[cur].r ) >>1 ;
    if(r <= mid ){//如果中点在r的右边,则应插入到左儿子
        insert(l,r,v,cur<<1);
    }
    else if( l >= mid ){//如果中点在l的左边,则应该插入到右儿子
        insert(l,r,v,cur<<1|1);
    }
    else {//否则,中点一定在s和t之间,把待插线段分成两半分别查到左右儿子里面
        insert(l,mid,v,cur<<1);

        insert(mid ,r ,v,cur<<1|1);
    }
}
//从根节点算起,计算每点颜色
void Calculate(int cur){
    if(a[cur].cor == -1){
        last = a[cur].cor;
        return ;
    }
    else if(a[cur].cor >= 0){
        if(a[cur].cor!=last){//表示该区间段颜色和父结点不一样,
            num[a[cur].cor]++;//num[t]表示颜色t出现的次数
            last = a[cur].cor;
        }
        return ;
    }
    else {
        Calculate(cur<<1);//查询左子树段
        Calculate(cur<<1|1);//...右..
    }
}
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF){
        int x1,x2,c;
        int c_max= - 1;
//        printf("~~~\n");
        build(0,8000,1);

        for(int i = 0 ; i < n ; i++){
            scanf("%d%d%d",&x1,&x2,&c);
            insert(x1,x2,c,1);
            if(c >= c_max)
                c_max= c;//记录颜色最大值
        }
        mem0(num);
        Calculate(1);
        for(int i = 0 ; i <= c_max ; i++){
            if(num[i] ){
                printf("%d %d\n",i,num[i]);
                num[i] = 0 ;
            }
        }
        puts("");
    }
//    system("pause");
    return 0;
}

0 0
原创粉丝点击