【poj 2528】Mayor's posters 题意&题解&代码(C++)

题目链接:
http://poj.org/problem?id=2528
题意:
n 个人依次贴海报,给出每张海报所贴的范围 li ,ri 求出最后还能看见多少张海报。
题解:
线段树,因为后来的海报总会覆盖之前张贴的海报,那么我们把操作从后往前枚举,用线段树 tr [ i ] . val 表示标号为 i 的节点所代表的区间中已经有多少个位置被覆盖。
然后就是简单的区间查询和区间修改。
然后看它的数据范围 10000000 直接线段树妥妥的MLE,需要用离散化,而且这个离散化还要注意一个细节,简单的排序后编号是不可以的,举一个例子:
3
1 10
1 4
6 10
直接排序后标号为

 vis[1]=1;vis[4]=2;vis[6]=3;vis[10]=4; 

然后照这样的做法,先覆盖 3~4 在覆盖 1~2 ,然后覆盖 1~4 ,答案是 2 ,然而正确答案是 3 ,中间的位置5被神奇的跳过了,新的离散方法就是,离散时若发现 a[i] - a[i-1] > 1 那么 vis [ a[i] ] = vis [ a[i-1] ] + 2 ,这样的话就相当于给中间那些数留出来了一个空位,防止上面的情况发生,具体细节看代码。

代码:

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<map>
#define lson (id*2)
#define rson (id*2+1)
using namespace std;
int ans;
struct node{ 
    int val;
    int lazy;
}tr[160005];
void pushup(int id)
{
    tr[id].val=tr[lson].val+tr[rson].val;
}
void pushdown(int id,int l,int r)
{
    if (tr[id].lazy)
    {
        int mid=(l+r)/2;
        tr[lson].val=mid-l+1;tr[lson].lazy=1;
        tr[rson].val=r-mid;tr[rson].lazy=1;
        tr[id].lazy=0;
    }
}
void build(int id,int l,int r)
{
    tr[id].lazy=0;
    if (l>=r) {tr[id].val=0;return ;}
    int mid=(l+r)/2;
    build(lson,l,mid);
    build(rson,mid+1,r);
    pushup(id);
    return ;
}
void add(int id,int l,int r,int L,int R,int v)
{
    if (l>r || L>r || R<l) return ;
    if (l>=L && r<=R) {tr[id].val=r-l+1;tr[id].lazy=1;return ;}
    int mid=(l+r)/2;
    pushdown(id,l,r);
    if (L<=mid) add(lson,l,mid,L,R,v);
    if (R>=mid+1) add(rson,mid+1,r,L,R,v);
    pushup(id);
}
void query(int id,int l,int r,int L,int R)
{
        if (l>r || L>r || R<l) return ;
        if (l>=L && r<=R) {ans+=tr[id].val;return ;}
        int mid=(l+r)/2;
        pushdown(id,l,r);
    if (L<=mid) query(lson,l,mid,L,R);
        if (R>=mid+1) query(rson,mid+1,r,L,R);
        pushup(id);
}
int zans,len,tot,T,n,m,l[10005],r[10005],a[20005];
map<int,int>vis;
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        tot=0;len=0;zans=0;
// vis.clear();
        for (int i=1;i<=n;i++)
        {
            scanf("%d%d",&l[i],&r[i]);
            tot++;a[tot]=l[i];
            tot++;a[tot]=r[i];
            if (l[i]>r[i]) swap(l[i],r[i]);
        }
        sort(a+1,a+1+tot);
        vis[a[1]]=1;
        len=1;

        for (int i=2;i<=tot;i++)
        if (a[i]==a[i-1]) continue;
        else if (a[i]-a[i-1]>1)
        len+=2,vis[a[i]]=len;
        else len++,vis[a[i]]=len;
        //cout<<tr[1].val<<endl;
        build(1,1,len);
    // for (int i=1;i<=len*4;i++)
    /// tr[i].val=0,tr[i].lazy=0;
        //cout<<tr[1].val<<endl;
        for (int i=n;i>=1;i--)
        {
            ans=0;query(1,1,len,vis[l[i]],vis[r[i]]);

            if (ans!=vis[r[i]]-vis[l[i]]+1)
            zans++,add(1,1,len,vis[l[i]],vis[r[i]],1);
            if (tr[1].val==len) break;
        }
        printf("%d\n",zans);
    }   
}

你可能感兴趣的:(线段树,poj)