1. 程式人生 > >zoj 1610 Count the Colors 線段樹,成段更新染色

zoj 1610 Count the Colors 線段樹,成段更新染色

Count the ColorsTime Limit:2000MS    Memory Limit:65536KB    64bit IO Format:%lld & %llu

Description

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

題意:對一段區間進行塗色,問最後每一種可見的顏色共佔多少個不連續的區間。

方法:線段樹+lazy標誌

思路:這到題目的關鍵一點是區間不能取閉區間,根據題意,為了方便可以取左開右閉,而且要搞明白塗色的是區間而不是點,因此根據線段樹不能一步得到結果,我們可以利用線段樹的延時更新策略,即一個節點表示一段區間,如果這段區間是純色的,那麼會在這個點上進行標記,於是就不需要對其子區間進行圖色了,除非下次圖色的時候發生覆蓋,才需要繼續向下更新,最終線段樹可以以較小的代價得到最終的色彩分佈,然後,我們再去線性掃描一遍這個分佈,就可以得到每種顏色的分佈,將顏色值作為陣列的下標,這樣在掃描完成後得到的資料就是按照顏色值的變化的。

#include <iostream>
#include <stdio.h>
#include <string.h>
#define maxn 8010
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;

int color[maxn<<2];
int distrb[maxn];//顏色分佈
int res[maxn];

void push_down(int rt)
{
    if(color[rt]!=-1)//如果有延時更新標誌
    {
        color[rt<<1]=color[rt<<1|1]=color[rt];//更新子節點的標誌
        color[rt]=-1;//更新父節點的標誌
    }
}

void update(int L,int R,int data,int l,int r,int rt)
{
    if(L<=l&&R>=r)//找到區間
    {
        color[rt]=data;
        return;
    }
    if(color[rt]==data)//如果該區間包含該標記
        return;
    push_down(rt);//向下更新
    int m=(l+r)>>1;
    if(L<=m)
        update(L,R,data,lson);
    if(R>m)
        update(L,R,data,rson);
}

void query(int l,int r,int rt)
{
    if(color[rt]!=-1)//該區間是純色的
    {
        for(int i=l; i<=r; i++)
            distrb[i]=color[rt];//將顏色的分佈還原
        return;
    }
    if(l!=r&&color[rt]==-1)//只有區間長度大於0才是有意義的
    {
        int m=(l+r)>>1;
        query(lson);
        query(rson);
    }

}



int main()
{
    int n,i;
    int left,right,data;
    int temp;
    while(~scanf("%d",&n))
    {
        memset(color,-1,sizeof(color));
        memset(distrb,-1,sizeof(distrb));
        while(n--)
        {
            scanf("%d%d%d",&left,&right,&data);
            update(left+1,right,data,1,maxn,1);//區間是左開右閉的
        }
        query(1,maxn,1);//查詢整個區間
        memset(res,0,sizeof(res));
        for(i=0;i<maxn;)//遍歷顏色分佈,統計不同的色塊
        {
            while(i<maxn&&distrb[i]==-1)
                i++;
            if(i>=maxn)
                break;
            temp=distrb[i];
            res[temp]++;
            while(i<maxn&&distrb[i]==temp)
                i++;
        }
        for(i=0;i<maxn;i++)//輸出
        {
            if(res[i]!=0)
                printf("%d %d\n",i,res[i]);
        }
        printf("\n");
    }
    return 0;
}