1. 程式人生 > >ZOJ1610(區間覆蓋問題+線段樹)

ZOJ1610(區間覆蓋問題+線段樹)

區間覆蓋問題,參考POJ2528的解法。(以下簡稱POJ2528為參考題)

1.對於輸入資料的處理:輸入和參考題不同,輸入的是染色區間的端點,而參考題輸入的是一段區間的編號。所以對資料進行輸入的處理,處理方式為:[0,4]相當於對四段區間覆蓋(也可以說染色):【0,1】,【1,2】,【2,3】,【3,4】我們根據參考題的解法對區間進行編號處理:將右端點的值作為區間的編號,這樣我們的輸入就可以實現端點到區間的轉換。就可以根據參考題的解法來處理。

處理方式:輸入L,R後,將L++.

2. 使用ret陣列來儲存每種顏色出現的段數。

3.注意下推函式中,在下推完成後必須對當前結點的標記刪除!否則一個非常重要的影響是:線上段樹中考慮該節點,我們更新該節點區間下的染色時,該節點底層的染色會被該節點的顏色覆蓋!

4.我們將tree[]陣列的初始值考慮成一種顏色-1,遍歷到底層時不能返回(將temp更新為-1)因為按照題意,不相鄰的兩端區間的染色(中間即使沒有其他顏色)也算作一種顏色的兩段。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<string>
using namespace std;
const int maxn=8000+10;
int tree[maxn<<4];
int ret[maxn];
int n,L,R,C;
void pushdown(int rt)
{
    tree[rt<<1]=tree[rt<<1|1]=tree[rt];
    tree[rt]=-1;
}
void update(int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        tree[rt]=C;
        return;
    }
    int m=(l+r)>>1;
    if(tree[rt]!=-1)
        pushdown(rt);
    if(L<=m)
        update(l,m,rt<<1);
    if(m<R)
        update(m+1,r,rt<<1|1);
}
int temp;//記錄上一個區域的顏色
void query(int l,int r,int rt)
{
    if(tree[rt]!=-1)
    {
        if(temp!=tree[rt])
            ret[tree[rt]]++;
        temp=tree[rt];
        //printf("運次到底層\n");
        return;
    }
    if(l==r)
    {
        temp=-1;
        return;
    }
    int m=(l+r)>>1;
    query(l,m,rt<<1);
    query(m+1,r,rt<<1|1);
}
int main()
{
    while(~scanf("%d",&n))
    {
        memset(tree,-1,sizeof(tree));
        memset(ret,0,sizeof(ret));
        for(int i=0; i<n; ++i)
        {
            scanf("%d%d%d",&L,&R,&C);
            L++;
            update(1,8001,1);
        }
        temp=-1;
        query(1,8001,1);
        for(int i=0; i<=8001; ++i)
            if(ret[i])
                printf("%d %d\n",i,ret[i]);
        puts("");
    }
    return 0;
}