POJ 2528 Mayor's posters (线段树,染色问题,离散化要注意)

做这题建议看一下该题的discuss。

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <set>
/*

题意:给出n张海报的左端点和右端点,按顺序往墙上贴。问最后整张墙能看到几张海报。

注意:按题意是如此够造树的,即每个点其实是一小块段。
|___|___|___|___|___|___|___|___|
  1   2   3   4   5   6   7   8

思路:相当于染色问题,这里我每个节点有个color值。
    color值有三种情况:1.0表示该区间为染色;2.-1表示该区间含有多种颜色;3.正整数表示该区间全是一种颜色
    每次更新(即第i次“涂色”)的时候,如果区间在范围内,则该区间color值替换为此次的颜色(用i表示)。
    最后查询的时候,从根节点往下查,直到查询到color值为某一个正整数,标记该颜色对应的序号。
    最后统计有多少个标记,即为答案。

由于数据大,要离散化,这才是重点!!!
有些人离散化,直接按顺序相邻,即每次都只加1。这是错误的!!!
给个数据就明白了:
1
3
1 10
1 3
6 10
正确答案:3
错误答案:2
忽略了顺序相邻但位置不相邻的情况
如果直接按顺序离散:
1 4
1 2
3 4
那么1 2和3 4的就会覆盖掉1 4,得出错误结果2
即离散的时候3和6之间应该还要留出一段,即总共离散为5段,不然会把中间夹的给覆盖掉了

所以离散的时候,排好序后,如果两个相邻的仅相差1,那么对应的映射+1即可。
但如果相差大于1,则对应的映射+2,留出个空隙。

在discuss里会有人说,如果按这正确的方法做,提交会WA;全部改成+1,才AC。
其实+2导致WA的原因,是数组开的不够。
我原本开的是tree[maxn<<3]的大小,用正确做法做,WA;但开大后,tree[maxn<<4],就AC了。
也就是说,POJ上其实没有这类数据

*/
using namespace std;
const int maxn=10005;
int n,m,idx;
int maxh; //对应映射的最大值
int hash_val[10000005]; //对应的映射
int val[maxn*2]; //存储端点的值
int vis[maxn]; //用来标记颜色
//存储海报的左端点、右端点
struct Pos{
    int left,right;
}pos[maxn];

struct Node{
    int color; //0:该区间没有染色;-1:该区间含多种颜色;正整数:该区间涂满一种颜色。
    bool lazy;
}tree[maxn<<4];  //10000个海报,每个海报两个端点,所以最多会有20000个点,但开4倍不够,要开8倍,这样+2的方法才能AC

void build(int rt,int L,int R){
    tree[rt].color=0;
    tree[rt].lazy=false;
    if(L==R)
        return;
    int mid=(L+R)>>1;
    build(rt<<1,L,mid);
    build(rt<<1|1,mid+1,R);
}

void pushUp(int rt){
    int lson=rt<<1,rson=rt<<1|1;
    //只要有一个子区间上面含多种颜色(color值为-1),该节点color值为-1
    if(tree[lson].color==-1 || tree[rson].color==-1)
        tree[rt].color=-1;
    //两个子区间都没涂有颜色
    else if(!tree[lson].color && !tree[rson].color)
        tree[rt].color=0;
    //两个子区间各自都涂有一种颜色
    else if(tree[lson].color && tree[rson].color){
        if(tree[lson].color==tree[rson].color)
            tree[rt].color=tree[lson].color;
        else
            tree[rt].color=-1;
    }
    else{
        //一个为0(即该区间没有染色),另一个为正数
        tree[rt].color=tree[lson].color|tree[rson].color;
    }
}
void pushDown(int rt){
    if(tree[rt].lazy){
        int lson=rt<<1,rson=rt<<1|1;
        tree[lson].color=tree[rson].color=tree[rt].color;
        tree[lson].lazy=tree[rson].lazy=true;
        tree[rt].lazy=false;
    }
}
void update(int rt,int l,int r,int L,int R,int color){
    if(l<=L && R<=r){
        tree[rt].lazy=true;
        tree[rt].color=color;
        return;
    }
    pushDown(rt);
    int mid=(L+R)>>1;
    if(r<=mid)
        update(rt<<1,l,r,L,mid,color);
    else if(l>mid)
        update(rt<<1|1,l,r,mid+1,R,color);
    else{
        update(rt<<1,l,mid,L,mid,color);
        update(rt<<1|1,mid+1,r,mid+1,R,color);
    }
    pushUp(rt);
}
void query(int rt,int L,int R){
    //下面两种情况已经包含了叶子节点,因为叶子节点的color只能为0或者>0,不可能为-1。所以不会RE
    if(tree[rt].color>0){
        //如果该区间涂有一种颜色,则标记该颜色
        vis[tree[rt].color]=1;
        return;
    }
    //如果区间没有染色,直接return。
    if(!tree[rt].color){
        return;
    }
    int mid=(L+R)>>1;
    query(rt<<1,L,mid);
    query(rt<<1|1,mid+1,R);
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        idx=0;
        for(int i=1;i<=n;i++){
            scanf("%d%d",&pos[i].left,&pos[i].right);
            val[idx++]=pos[i].left;
            val[idx++]=pos[i].right;
        }
        sort(val,val+idx);
        hash_val[val[0]]=1;
        //离散
        for(int i=1;i<idx;i++){
            if(val[i]==val[i-1])
                hash_val[val[i]]=hash_val[val[i-1]];
            //如果两个端点不相邻,则+2
            else if(val[i]-val[i-1]>1)
                hash_val[val[i]]=hash_val[val[i-1]]+2;

            //如果两个端点相邻,则+1.
            else{
                hash_val[val[i]]=hash_val[val[i-1]]+1;
            }
            maxh=hash_val[val[i]];
        }
        build(1,1,maxh);
        for(int i=1;i<=n;i++){
            update(1,hash_val[pos[i].left],hash_val[pos[i].right],1,maxh,i);
        }
        memset(vis,0,sizeof(vis));
        query(1,1,maxh);
        int ans=0;
        for(int i=1;i<=n;i++){
            if(vis[i]){
                ans++;
            }
        }
        printf("%d
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/chenxiwenruo/p/3389410.html