(重温)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;
}


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