(重溫)poj 2528 Mayor's posters 線段樹 染色+離散化

這題是前年做過的題目,不過那時候比較水,看別人的解題報告寫着就混過去了,於是今天又重做了一次。

這題算是比較經典的線段染色問題了,

但是我在POJ上很多人數據有問題,或者說無限WA,我總結了一下,舉一個簡單的數據

3

1 10

6 10

1 3

大家很多人離散化就變成

1 3 6 10

1 2 3 4

於是先覆蓋了

1 4

3 4

1 2

答案爲2,其實爲3

爲什麼 因爲正常的沒離散化的相鄰兩個數就是相鄰的,離散化後,相鄰的兩個數其實可能相差很大。

所以應該把線段樹寫成線段的形勢

即葉子節點爲 0 - 1 替代 常用的 1- 1 而表示 1

於是上面的數據則變成了這樣

                 0 10

          0 3        3 10

                    3  5 5  10

這樣覆蓋後就能得到正確的答案3了。

詳見代碼。

#include<cstdio>
#include<algorithm>
#include<cstring>
const int maxn = 10009;
int color[maxn<<3];
int a[maxn<<1];
int b[maxn<<1];
bool vi[maxn];
void pushdown(int rt){
    if(color[rt]>0){
        color[rt<<1]=color[rt<<1|1]=color[rt];
    }
    color[rt]=-1;
}
void update(int rt,int l,int r,int L,int R,int c){
    if(b[l]>=L&&b[r]<=R){
        color[rt] = c;
        return;
    }
    pushdown(rt);
    int mid = (l+r)>>1;
    if(b[mid]>L)update(rt<<1,l,mid,L,R,c);
    if(b[mid]<R) update(rt<<1|1,mid,r,L,R,c);
}
int dfs(int rt){
    int ans = 0;
  //  printf("%d\n",color[rt]);
    if(color[rt]>0 && !vi[color[rt]]){
        vi[color[rt]] = true;
        ans++;
    }else if(color[rt]==-1){
        ans+=dfs(rt<<1);
        ans+=dfs(rt<<1|1);
    }
    color[rt] = 0;
    return ans;
}
int main(){
    int _case,l,r;scanf("%d", &_case);
    while(_case--){
        int n;scanf("%d", &n);
        for(int i=0;i<n;i++){
            scanf("%d%d",&l,&r);
            b[2*i]=a[2*i]=l-1;
            b[2*i+1]=a[2*i+1]=r;
        }
        std::sort(b,b+2*n);
        int num = std::unique(b,b+2*n)-b;
        num--;
     //   printf("num:%d \n",num);
        for(int i=0;i<n;i++){
            update(1,0,num,a[2*i],a[2*i+1],i+1);
        }
    //    for(int i=1;i<=n;i++) printf("%d %d\n",i,vi[i]);
        printf("%d\n",dfs(1));
        memset(vi, false, sizeof(vi));
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章