当前位置: 首页 > article >正文

POJ 1201 Intervals 线段树

一、题目大意

给我们一些闭区间[ai , bi],其中 1 <= ai <= bi <= 50000,让我们求出一个集合,使得这个集合与 区间 [ai , bi]有 ci个共同元素,对于所有的 1<=i <=n个区间而言。

二、解题思路

根据题目范围,我们可以对 1到50000的数字进行循环,然后每次循环中用线段树进行操作,O(n*logn)的复杂性时间上可行。

1、我们可以把所有的区间按照区间的起点进行排序,然后计算出每个区间的 bi - ci + 1,用线段树维护各个区间的 bi - ci + 1的最小值。

2、针对每次循环的数字 num,只需要用二分确定 ai 小于等于它的范围 R,然后从线段树中查询出其中最小的 bi - ci + 1,如果 bi - ci + 1 == num,代表这个数字需要被选择,答案加一,同时需要更新线段树上的[0 , R) 内所有的 bi - ci + 1 值为原来的值 + 1

3、每次循环 num后,判断 num 是否等于某个区间的 bi,如果等于,则将对应的 bi 在线段树上的节点的 bi - ci + 1 设置为50007(50000以上则为废弃节点,因为大于所有的num),然后循环向上更新父节点即可。

本题目的线段树需要实现以下两个功能。

1、查询 [0 , R)的 bi - ci + 1的最小值

2、更新[0, R)范围内所有的 bi - ci + 1

那么我们需要让线段树上保存两个值

1、[0, R)区间内集体加上的值(dat)

2、[0 , R)内去掉第1点剩余部分的最小值(rmq)。

这样对于查询操作时,只需要加上所有父节点及自己的 dat,和自身的rmq即可。

对于更新操作时,只需要更新自己的dat,

并递归所有父节点的 rmq[parent]=min(rmq[lch]+dat[lch],rmq[rch]+dat[rch])即可。

总结:每次利用RMQ求出 a1 <=  num范围内的 bi - ci + 1的最小值,与num进行比较,即可知道这个数字是需要选择,接下来在树上废弃掉 bi <= num的节点即可不会被已经经过的区间影响,同时如果这个数字被选择,更新 a1 <= num的全部节点 为原来的值+1,这样代表这些区间内都加入了一个有效元素,以为下次循环做铺垫。

三、代码

#include <iostream>
#include <algorithm>
using namespace std;
typedef pair<int, int> P;
P sortByA[50007], sortByB[50007];
int rmq[131072], dat[131072], a[50009], b[50009], c[50009], n, _current, maxt, ans;
void input()
{
    scanf("%d", &n);
    maxt = 0, ans = 0;
    for (int i = 0; i < n; i++)
    {
        scanf("%d%d%d", &a[i], &b[i], &c[i]);
        maxt = max(maxt, b[i]);
        sortByA[i].first = a[i];
        sortByA[i].second = i;
    }
    sort(sortByA, sortByA + n);
    for (int i = 0; i < n; i++)
    {
        sortByB[i].first = b[sortByA[i].second];
        sortByB[i].second = i;
    }
    sort(sortByB, sortByB + n);
}
void build(int i, int l, int r)
{
    if (r - l == 1)
    {
        rmq[i] = b[sortByA[l].second] - c[sortByA[l].second] + 1;
    }
    else
    {
        int lch = i * 2 + 1;
        int rch = i * 2 + 2;
        build(lch, l, (l + r) / 2);
        build(rch, (l + r) / 2, r);
        rmq[i] = min(rmq[lch], rmq[rch]);
    }
}
int query(int _l, int _r, int i, int l, int r)
{
    if (_l >= r || _r <= l)
    {
        return 50007;
    }
    else if (l >= _l && r <= _r)
    {
        return rmq[i] + dat[i];
    }
    else
    {
        if (dat[i] > 50000)
        {
            return dat[i];
        }
        int lch = query(_l, _r, i * 2 + 1, l, (l + r) / 2);
        int rch = query(_l, _r, i * 2 + 2, (l + r) / 2, r);
        return min(lch, rch) + dat[i];
    }
}
void update(int _l, int _r, int i, int l, int r, int v)
{
    if (_l >= r || _r <= l)
    {
    }
    else if (l >= _l && r <= _r)
    {
        dat[i] += v;
        int j = i;
        while (j > 0)
        {
            j = (j - 1) / 2;
            rmq[j] = min(rmq[j * 2 + 1] + dat[j * 2 + 1], rmq[j * 2 + 2] + dat[j * 2 + 2]);
        }
    }
    else
    {
        update(_l, _r, i * 2 + 1, l, (l + r) / 2, v);
        update(_l, _r, i * 2 + 2, (l + r) / 2, r, v);
    }
}
void solveItem()
{
    int idx = upper_bound(sortByA, sortByA + n, P(_current, 0x3f3f3f3f)) - sortByA;
    if (idx <= 0)
    {
        return;
    }
    int mint = query(0, idx, 0, 0, n);
    if (mint == _current)
    {
        update(0, idx, 0, 0, n, 1);
        ans++;
    }
    int past = lower_bound(sortByB, sortByB + n, P(_current, -0x3f3f3f3f)) - sortByB;
    for (int j = past; j < n; j++)
    {
        if (sortByB[j].first != _current)
        {
            break;
        }
        update(sortByB[j].second, sortByB[j].second + 1, 0, 0, n, 50007);
    }
}
void solve()
{
    for (int i = 0; i <= maxt; i++)
    {
        _current = i;
        solveItem();
    }
}
int main()
{
    input();
    build(0, 0, n);
    solve();
    printf("%d\n", ans);
    return 0;
}

四、运行情况


http://www.kler.cn/a/108702.html

相关文章:

  • 【OceanBase 诊断调优】—— ocp上针对OB租户CPU消耗计算逻辑
  • 【初阶数据结构与算法】链表刷题之移除链表元素、反转链表、找中间节点、合并有序链表、链表的回文结构
  • 并发基础:(淘宝笔试题)三个线程分别打印 A,B,C,要求这三个线程一起运行,打印 n 次,输出形如“ABCABCABC....”的字符串【举一反三】
  • 基于迭代重加权最小二乘法的算法及例程
  • pip3 install -e .[stable]讲解
  • MySQL:CRUD
  • 微信小程序之投票管理
  • Leetcode—274.H指数【中等】
  • Java 四种引用类型
  • 【网络协议】聊聊TCP如何做到可靠传输的
  • redis 常用方法
  • 71 搜索二维矩阵
  • 大数据之LibrA数据库常见术语(十)
  • Springmvc 讲解(1)
  • 嵌入式开发
  • Animate(原Flash)和木疙瘩中遮罩动画秒懂
  • 黑客在Pwn2Own Toronto上以58个零日漏洞赚取超过100万美元
  • dump与strace命令实战之分析keystore死锁导致watchdog问题
  • 正向代理和反向代理
  • 基于springboot实现校园疫情防控系统项目【项目源码+论文说明】计算机毕业设计
  • 【多线程面试题 八】、说一说Java同步机制中的wait和notify
  • 如何借助数据集更好的评估NLP模型的性能?
  • 【数据结构】数组和字符串(九):稀疏矩阵的链接存储:十字链表的插入、查找、删除操作
  • 大数据可视化BI分析工具Apache Superset实现公网远程访问
  • 【数据结构】Map和Set
  • 深入浅出排序算法之基数排序