POJ 2528 Mayor's posters

大概题意:有一面很长的墙,按照输入顺序往上面贴海报(每张海报的宽度和墙都相同,所以输入数据给的只有海报的左端坐标和有段坐标)问最后可以看见几张海报(只看见一部分也算看见);

分析:观察数据范围1000W这么大的数字,直接做的话必然会爆内存和超时,所以要进行离散化(这是本人的做的第一道要使用离散化的题目,还好离散化的部分比较容易),海报的数字却只有10000,所以出现的数字(坐标)最多就是20000,我们可以吧所有出现的数字按从小到大标号,用标号的大小来判断数字的大小;由于即使离散化了数据任然很大,所以这里使用线段树;这里是成段更新的线段树,这里每个节点有三个属性(left、right、color)前两个没什么特殊的,主要说明一下color这个元素,表示海报的颜色,如果这个left-right之间这一条线段有颜色切唯一的话color才会有值,最后把树建好了之后再写一个DFS(这个DFS比较简短就不多说了)计算有多少种不同的颜色,看到这里应该就可以敲这道题了;

以下是我的AC代码:(水平较低,仅供参考)

/*
Problem: 2528		User: Burglar
Memory: 2236K		Time: 63MS
Language: G++		Result: Accepted
*/
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <string.h>
#include <iostream>
#define MAXN 10005
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
#define lrt rt<<1
#define rrt rt<<1|1
using namespace std;
struct Node
{
    int point;//记录数字
    int num;//记录这个数字来自于哪一个输入数据
}line[MAXN<<3];//数组一定要记得开大些刚开始时4被结果WA了
struct Input_line
{
    int l,r;
    int color;
}input_line[MAXN];//输入
struct Tree
{
    int left,right;
    int color;
}tree[MAXN<<3];//树
int n,ans;
int judge[MAXN];
bool cmp(Node a,Node b)//用来对数字排序
{
    return a.point<b.point;
}
void Build(int l,int r,int rt)//建树
{
    tree[rt].left=l;
    tree[rt].right=r;
    tree[rt].color=0;
    if(l==r) return;
    int m=(l+r)>>1;
    Build(lson);
    Build(rson);
    return;
}
void update(int color,int l,int r,int rt)
{
    if(tree[rt].left==l&&tree[rt].right==r)//正好完全覆盖住
    {
        tree[rt].color=color;
        return;
    }
    if(tree[rt].color!=0)
    {
        tree[rt<<1].color=tree[rt<<1|1].color=tree[rt].color;//吧这个根节点的颜色付给他的两个儿子,让后再归零
        tree[rt].color=0;
    }
    if(l>=tree[rrt].left) update(color,l,r,rrt);//完全在右边
    else if(r<=tree[lrt].right) update(color,l,r,lrt);//完全在左边
    else//左右两边都有
    {
        update(color,l,tree[lrt].right,lrt);
        update(color,tree[rrt].left,r,rrt);
    }
    return;
}
void DFS(int rt)//用递归的方式记录答案
{
    if(tree[rt].color!=0)
    {
        if(!judge[tree[rt].color])
        {
            ans++;
            judge[tree[rt].color]=1;
        }
        return;
    }
    else
    {
        DFS(rt<<1);
        DFS(rt<<1|1);
    }
    return;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        memset(line,0,sizeof(line));
        memset(judge,0,sizeof(judge));
        ans=0;
        scanf("%d",&n);
        for(int i=0;i<n;i++)//离散化的过程
        {
            scanf("%d%d",&input_line[i].l,&input_line[i].r);
            input_line[i].color=i+1;
            line[i<<1].point=input_line[i].l;
            line[i<<1].num=-(i+1);//用复数表示左边,应为i从0开始如果不加一的话就不能通过正负来判断左边还是右边;
            line[i<<1|1].point=input_line[i].r;
            line[i<<1|1].num=(i+1);
        }
        sort(line,line+(n<<1),cmp);
        int next_point=line[0].point;
        int num_point=1;
        for(int i=0;i<(n<<1);i++)
        {
            if(next_point!=line[i].point)
            {
                num_point++;
                next_point=line[i].point;
            }
            if(line[i].num<0)
                input_line[-line[i].num-1].l=num_point;
            else
                input_line[line[i].num-1].r=num_point;
        }
        Build(1,num_point,1);
        for(int i=0;i<n;i++)
        {
            update(input_line[i].color,input_line[i].l,input_line[i].r,1);
        }
        DFS(1);
        printf("%d\n",ans);
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值