Mayor's posters OpenJ_Bailian -POJ - 2528 (离散化算法)

Mayor’s posters OpenJ_Bailian - 2528

题目 我就 不 写出来拉 ,简单 依据这道题 来简单的说一下 离散化算法。 离散化算法 是一种 将 许多 很大 的 空间 根据 这些空间 的相对关系 ,进行 离散化 ,将 这些大空间 转变为 与之 一一对应的 小空间 ,进而 减少 数据的大小 ,简化 运算。可以进行离散化 的 条件: 是 这些 大空间 在 运算中 与他们的 具体的大小 无关, 而只与他们 的先对 位置 有关 。 这道题 对应的 大空间 是 线段 ,由于 线段 的 范围很大 1 =》 10000000,而且 题目 的答案 只与这些线段 的相对 位置 有关 ,所以可以 对这些 线段 进行 离散化 ,下面 说一下 怎样 进行离散化:

这个 题 是要根据 线段树 来做的 ,可以根据 离散化 对数据 进行处理,其中 样例 的 数据 处理后为:(1, 4), (2, 5), (7, 8), (3, 4), (6, 8)
但是写到这里 , 还有个问题 ,要怎么 用线段树 ,寻找 宣传海报的 的数量呢? 我想了 一个方法 就是 当上面的数据 都处理 完之后, 不用 线段树更新 数据, 直接 查找数据, 而且还是 逆序 输入数据 , 具体 过程见下面的 代码!

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

int n;
int pos[10006][2];// 存储 输入的 数据 
bool vis[10000007];// 标记 作用 
int sett[30000];// 存储 所有的点 , 用来 排序的
int temp[10000007];// 对数据进行离散化处理的数组

bool cmp(const int a, const int b)
{
    return a < b;
}

struct TreeNode
{
    int date;// 标记作用
}tree[8*10006]; // 最多有 2 * 10000 个 不同的 点 ,乘上 4  之后 可以保证有足够的空间建树

void Build(int root, int s, int e)
{
    tree[root].date = 0;// 初始化 为  0  表示 没有标记
    if(s == e)
        return ;
    int mid = (s + e)/2;
    Build(root*2, s, mid);
    Build(root*2+1, mid+1, e);
}

int Query(int root, int s, int e, int qs, int qe)
{
    if(tree[root].date == 1)// 表示 该区间 在后面 有海报 会将之覆盖 
        return 0;
    if(qs == s && e == qe)
    {
        tree[root].date = 1;
        return 1;
    }

    int mid = (s + e)/2;
    int ans;
    if(qe <= mid)
        ans = Query(root*2, s, mid, qs, qe);
    else if(qs >= mid+1)
        ans = Query(root*2+1, mid+1, e, qs, qe);
    else
        ans = Query(root*2, s, mid, qs, mid) | Query(root*2+1, mid+1, e, mid+1, qe);// 左右区间 只要有一个 存在不被 覆盖 的 区间 就可以
    if(tree[root*2].date && tree[root*2+1].date)// 由左右子节点的状态 推出父节点的状态
        tree[root].date = 1;
    return ans;
}

int main()
{
    int t; cin>>t;

    while(t--)
    {
        scanf("%d", &n);
        memset(vis, false, sizeof(vis));
        // 下面是 离散化处理的过程  现存储  再去重排序 再数据更新为 离散化之后的数据
        int k = 0;
        for(int i = 0; i < n; i++)
        {
            scanf("%d%d", &pos[i][0], &pos[i][1]);
            if(!vis[pos[i][0]])// 去重
            {
                sett[k++] = pos[i][0];
                vis[pos[i][0]] = true;
            }
            if(!vis[pos[i][1]])// 去重
            {
                sett[k++] = pos[i][1];
                vis[pos[i][1]] = true;
            }
        }
        sort(sett, sett+k, cmp);// 从小到大 排序

        for(int i = 0; i < k; i++)
            temp[sett[i]] = i + 1;// 将 数据离散化  seet【i】 =》i+1

        int sum = 0;
        Build(1, 1, k);// 因为离散化之后的数据的范围  为  1 =》 k 
        for(int i = n-1; i >= 0; i--)// 逆序 输入数据
        {
            pos[i][0] = temp[pos[i][0]];
            pos[i][1] = temp[pos[i][1]];
            if(Query(1, 1, k, pos[i][0], pos[i][1]) > 0)
                sum++;
        }

        printf("%d\n", sum);
    }

    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值