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,不过用线段切割做代码相当的简洁

你可能感兴趣的:(post)