POJ 2528 Mayor's posters.

~~~~

一直MLE,才发现要写离散化操作。其他就是线段树的成段更新(每次用不同标记去更新区间),最后统计下有多少种标记就OK了。

题目链接:http://poj.org/problem?id=2528

大牛写的很详细,请戳:http://blog.youkuaiyun.com/metalseed/article/details/8041334

~~~~

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 11111
#define lson rt<<1,s,m
#define rson rt<<1|1,m+1,e
using namespace std;

int x[N<<2]; //因为有离散化操作,注意数组大小,否则会RE。
int ans[N<<2];
int s[N],e[N];
int tre[N<<4];
void pushdown(int rt,int m)
{
    if(tre[rt])
    {
        tre[rt<<1]=tre[rt<<1|1]=tre[rt];
        tre[rt]=0;
    }
}
void update(int l,int r,int val,int rt,int s,int e)
{
    if(l<=s && r>=e)
    {
        tre[rt] = val;
        return ;
    }
    pushdown(rt,e-s+1);
    int m=(s+e)>>1;
    if(r<=m) update(l,r,val,lson);
    else if(l>m) update(l,r,val,rson);
    else
    {
        update(l,m,val,lson);
        update(m+1,r,val,rson);
    }
}
int query(int pos,int rt,int s,int e)
{
    if(s==e)
        return tre[rt];
    pushdown(rt,e-s+1);
    int m=(s+e)>>1;
    if(pos<=m) query(pos,lson);
    else query(pos,rson);
}
int bin(int key,int ma)
{
    int l=0,r=ma,m=0;
    while(l<=r)
    {
        m=(l+r)>>1;
        if(x[m]==key) return m;
        else if(x[m]>key) r=m-1;
        else l=m+1;
    }
    //return -1;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int m;
        scanf("%d",&m);
        int n=0;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&s[i],&e[i]);
            x[n++]=s[i];
            x[n++]=e[i];
        }
        int cnt=1;
        sort(x,x+n);
        //删去重复的元素,
        for(int i=1;i<n;i++)
            if(x[i]!=x[i-1]) x[cnt++]=x[i];
        //离散化技巧:凸显间隔(否则可能会有问题)。
        for(int i=cnt-1;i>0;i--)
            if(x[i]!=x[i-1]+1) x[cnt++]=x[i-1]+1;
        //再一次排序,便于后面二分离散化。
        sort(x,x+cnt);
        memset(tre,0,sizeof(tre)); //相当于建树过程
        for(int i=1;i<=m;i++)
        {
            int l=bin(s[i],cnt-1);
            int r=bin(e[i],cnt-1);
            update(l,r,i,1,0,cnt-1); //依次标记
        }
        int q=0;
        for(int i=0;i<cnt;i++)
        {
            int k=query(i,1,0,cnt-1);
            if(k) ans[q++]=k;  //~~
        }
        sort(ans,ans+q);
        int tot=1;
        for(int i=1;i<q;i++)
            if(ans[i]!=ans[i-1]) tot++;
        printf("%d\n",tot);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值