POJ2528 Mayor's posters(区间替换&&线段切割)

题目大意

在墙上贴海报,海报可以相互覆盖,问最后能够看到多少种海报

题解

方法一:线段树

嘛,就是区间染色问题,和POJ2777一样,不过颜色的种类比POJ2777多多了,最多有10000种。。。所以不能用位运算计算出颜色的总数量来。我们用另外一种方法,多了一个查询函数,在进行完海报的覆盖之后,对整个线段树进行一次查询,查询未清除的标记(碰到一个为标记的标记就回溯),未标记的种类总数就是最终可以看到的海报种类。WA了好多次。。。离散化的时候对位置进行排序的时候被坑了。。。我的离散化是有缺陷的。。。不过POJ数据太弱。。。居然AC了。。。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<bitset>
#define MAXN 10005
#define lson l,m,s<<1
#define rson m+1,r,s<<1|1
using namespace std;
int setv[MAXN<<2];
bool hash[MAXN<<2];
int cnt;
typedef struct {
    int p;
    int id;
} NODE;
NODE a[MAXN*2];
bool cmp(NODE a,NODE b) {
    return a.p<b.p;
}
bool cmp2(NODE a,NODE b) {
    if(a.id==b.id)
        return a.p<b.p;
    return a.id<b.id;
}
void PushDown(int s) {
    if(setv[s]) {
        setv[s<<1]=setv[s<<1|1]=setv[s];
        setv[s]=0;
    }
}
void update(int ql,int qr,int l,int r,int s,int d ) {
    if(ql<=l&&r<=qr) {
        setv[s]=d;
        return;
    }
    PushDown(s);
    int m=(l+r)>>1;
    if(ql<=m) update(ql,qr,lson,d);
    if(qr>m) update(ql,qr,rson,d);
}
void query(int l,int r,int s) {
    if(setv[s]) {
        if(!hash[setv[s]]) {
            cnt++;
            hash[setv[s]]=true;
        }
        return;
    }
    if(l==r) return;
    int m=(l+r)>>1;
    query(lson);
    query(rson);
}
int main(void) {
    int n,T;
    cin>>T;
    while(T--) {
        scanf("%d",&n);
        for(int i=1; i<=n; i++) {
            scanf("%d%d",&a[2*i-1].p,&a[2*i].p);
            a[2*i-1].id=a[2*i].id=i;
        }
        sort(a+1,a+2*n+1,cmp);
        int pre=-1;
        int k=0;
        for(int i=1; i<=2*n; i++) {
            if(pre!=a[i].p) {
                pre=a[i].p;
                a[i].p=++k;
            } else
                a[i].p=k;
        }
        sort(a+1,a+2*n+1,cmp2);
        memset(setv,0,sizeof(setv));
        for(int i=1; i<=n; i++)
            update(a[2*i-1].p,a[i*2].p,1,k,1,i);
        memset(hash,false,sizeof(hash));
        cnt=0;
        query(1,k,1);
        printf("%d\n",cnt);
      //  for(int i=1; i<=15; i++)
            //cout<<setv[i]<<endl;
    }
    return 0;
}

方法二:线段切割

可以作为线段切割的模板题了。。。USACO3.1.4 Shaping Regions的一维形式,直接看代码吧。。应该很容易懂。。。

#include<iostream>
#include<cstdio>
#include<cstring>
#define MAXN 10005
using namespace std;
typedef struct {
    int l;
    int r;
} NODE;
NODE a[MAXN];
bool f[MAXN];
int n,ans;
void cut(int l,int r,int col,int step) {
    while((step<n) &&(r<a[step].l||l>a[step].r)) step++;
    if(step>=n) {
        if(!f[col]) {
            ans++;
            f[col]=true;
        }
        return;
    }
    if(l<a[step].l) cut(l,a[step].l-1,col,step+1);
    if(a[step].r<r) cut(a[step].r+1,r,col,step+1);
}
int main(void) {
    int T;
    scanf("%d",&T);
    while(T--) {
        scanf("%d",&n);
        for(int i=0; i<n; i++)
            scanf("%d%d",&a[i].l,&a[i].r);
        memset(f,false,sizeof(f));
        ans=1;
        f[n-1]=true;
        for(int i=n-2; i>=0; i--)
            cut(a[i].l,a[i].r,i,i+1);
        printf("%d\n",ans);
    }
    return 0;
}

方法一用了94ms,方法二用了250ms,不过用线段切割做代码相当的简洁

原文地址:https://www.cnblogs.com/zjbztianya/p/3079974.html