题解 QOJ2559【Endless Road】/ SS241006D【套路题】

Petrozavodsk Winter 2022. Day 2. KAIST Contest + KOI TST 2021
XXII Open Cup named after E.V. Pankratiev, Grand Prix of Daejeon

题目描述

现在有 \(10^9\) 个花盆,依次编号为 \(1,2,\dots,10^{9}\)

给定 \(n\) 个二元组 \(L_i,R_i(L_i<R_i)\) ,我们将进行 \(n\) 次以下操作:

  1. 设当前第 \(i\) 个二元组的权值是满足花盆 \(x\) 为空且 \(L_i<x\le R_i\)\(x\) 数量。选出未被选过且权值最小的二元组 \(p\) 。如果存在多个权值最小的二元组,选择其中编号最小的。

  2. 对于 \(L_p<x\le R_p\) ,在花盆 \(x\) 中种上花。

请求出每次操作选择出的二元组 \(p\)

保证对于 \(1\le i<j\le n,R_i-L_i\le R_j-L_j\)

对于所有数据,\(1\le n\le 2.5\times 10^5,0\le L_i<R_i\le 10^{9}\),对于 \(1\le i<j\le n\)\(R_i-L_i\le R_j-L_j\)

solution

改成左闭右开。离散化。跳过一些暴力后,我们发现:两个互相包含的区间 \(i<j, [L_i, R_i)\subseteq[L_j, R_j)\),无论如何操作,都是 \(i\) 先被栽种,\(j\) 后被栽种。可以对花盆的位置分类,发现 \(i\) 区间的权值总是不大于 \(j\) 的。而如果我们去掉包含其它区间的区间,剩下的都是左、右断点分别单调的区间(称作合法区间),对这些合法区间我们将其存放在线段树上它们各自左端点的位置,然后可以二分、懒标记等一系列操作进行栽种(发现权值减少的合法区间的左端点连续)。

剩下的问题是删除一个合法区间后怎么找到新的合法区间。我们将所有区间按照右端点升序为第一关键字,左端点降序为第二关键字,以及自身编号升序为第三关键字,对所有区间进行排序,使每个区间获得一个排名。这样排序后,两个互相包含的区间 \(i<j, [L_i, R_i)\subseteq[L_j, R_j)\)\(i\) 的排名一定比 \(j\) 小(相当于给这个包含关系的 DAG 找了一个拓扑序)。于是,我们在删除一个合法区间时,先找到小于这个合法区间的左端点的最大的左端点(即其前一个合法区间的左端点,记为 \(t\)),新的区间的左端点起码需要 \(>t\);再找到大于这个合法区间的排名的最小排名(即其后一个合法区间的排名,记为 \(q\)),新的区间的排名若 \(\geq q\) 则它的右端点一定 \(\geq q\) 的右端点,也不合法(取等的情况讨论一下发现也对)。有了这两个限制,我们找到的就都是合法区间。

用另一棵线段树将所有非法区间存放在线段树上它们各自排名的位置,每次删除区间时,记删除的区间的排名为 \(x\),去找排名在 \([x, n]\) 中左端点 \(>t\) 的一个非法区间,若其排名 \(\geq q\) 则结束;否则将其升变为合法区间,并使 \(t\gets\) 其左端点。

至此可以在 \(O(n\log n)\) 的时间复杂度内解决原问题。

code

需要开两棵线段树,支持的线段树二分都有所不同。找 \(t,q\) 可以用一个 std::set,因为合法区间按照排名、或者左端点、或者右端点排序的结果都是一样的,可以随便写。插入新的合法区间时需要知晓其权值,使用另一个树状数组维护。seg1 是合法区间,seg2 是非法区间。

#include <bits/stdc++.h>
using namespace std;
#ifdef LOCAL
#define debug(...) ((void)fprintf(stderr, ##__VA_ARGS__))
#else
#define endl "\n"
#define debug(...) ((void)0)
#endif
using LL = long long;
template <int N, class T>
struct fenwick {/*{{{*/T c[N + 10];fenwick() { memset(c, 0, sizeof c); }void add(int p, T k) { for (; p <= N; p += p & -p) c[p] += k; }T qry(int p) { T r = 0; for (; p >= 1; p -= p & -p) r += c[p]; return r; }
};/*}}}*/
template <class T>
struct flower {/*{{{*/vector<T> vec;template <class U> flower& operator<<(U&& x) {vec.push_back(forward<U>(x));return *this;}size_t build() {auto bg = vec.begin(), ed = vec.end();sort(bg, ed);vec.erase(unique(bg, ed), ed);return vec.size();}size_t operator()(const T& x) const {return lower_bound(vec.begin(), vec.end(), x) - vec.begin();}T operator[](int i) const { return vec[i]; }
};/*}}}*/
struct range {int l, r, id;
} a[250010];
int n, m, nxt[500010], wh[500010];
int findnxt(int x) { return nxt[x] == x ? x : nxt[x] = findnxt(nxt[x]); }
flower<int> hua;
fenwick<500010, int> fen;
set<int> st;
namespace seg2 {constexpr int N = 2.5e5;int maxl[N << 2];void maintain(int p) { maxl[p] = max(maxl[p << 1], maxl[p << 1 | 1]); }void build(int p, int l, int r) {/*{{{*/if (l == r) {maxl[p] = -1e9;return ;}int mid = (l + r) >> 1;build(p << 1, l, mid);build(p << 1 | 1, mid + 1, r);maintain(p);}/*}}}*/void setValue(int x, int v, int p, int l, int r) {/*{{{*/if (l == r) {maxl[p] = v;return ;}int mid = (l + r) >> 1;if (x <= mid) setValue(x, v, p << 1, l, mid);else setValue(x, v, p << 1 | 1, mid + 1, r);maintain(p);}/*}}}*/int binary(int L, int R, int v, int p, int l, int r) {if (L <= l && r <= R) {if (maxl[p] <= v) return n + 1;if (l == r) return l;}int mid = (l + r) >> 1;int ret = L <= mid ? binary(L, R, v, p << 1, l, mid) : n + 1;if (ret <= n) return ret;return mid < R ? binary(L, R, v, p << 1 | 1, mid + 1, r) : n + 1;}void enable(int id) { debug("seg2::enable(%d)\n", a[id].id); setValue(id, a[id].l, 1, 1, n); }void disable(int id) { debug("seg2::disable(%d)\n", a[id].id); setValue(id, -1e9, 1, 1, n); }
};
namespace seg1 {constexpr int N = 5e5;pair<int, int> ans[N << 2];int tag[N << 2], maxr[N << 2];void maintain(int p) {ans[p] = min(ans[p << 1], ans[p << 1 | 1]);maxr[p] = max(maxr[p << 1], maxr[p << 1 | 1]);}void spread(int p, int k) { ans[p].first -= k, tag[p] += k; }void pushdown(int p) { spread(p << 1, tag[p]), spread(p << 1 | 1, tag[p]), tag[p] = 0; }void build(int p, int l, int r) {/*{{{*/tag[p] = 0;if (l == r) {ans[p] = make_pair(1e9, -1);maxr[p] = -1e9;return ;}int mid = (l + r) >> 1;build(p << 1, l, mid);build(p << 1 | 1, mid + 1, r);maintain(p);}/*}}}*/void setValue(int x, int id, int p, int l, int r) {/*{{{*/if (l == r) {if (id > 0) {int len = hua[a[id].r - 1] - hua[a[id].l - 1];int lenp = fen.qry(a[id].r - 1) - fen.qry(a[id].l - 1);ans[p] = make_pair(len - lenp, a[id].id);maxr[p] = a[id].r;} else {ans[p] = make_pair(1e9, -1);maxr[p] = -1e9;}return ;}int mid = (l + r) >> 1;pushdown(p);if (x <= mid) setValue(x, id, p << 1, l, mid);else setValue(x, id, p << 1 | 1, mid + 1, r);maintain(p);}/*}}}*/void modify(int L, int R, int k, int p, int l, int r) {/*{{{*/if (L <= l && r <= R) return spread(p, k);int mid = (l + r) >> 1;pushdown(p);if (L <= mid) modify(L, R, k, p << 1, l, mid);if (mid < R) modify(L, R, k, p << 1 | 1, mid + 1, r);maintain(p);}/*}}}*/void enable(int id) {debug("seg1::enable(%d) = [%d, %d]\n", a[id].id, a[id].l, a[id].r);st.insert(id);setValue(a[id].l, id, 1, 1, m);}void disable(int id) { debug("seg1::disable(%d) = [%d, %d]\n", a[id].id, a[id].l, a[id].r);assert(st.find(id) != st.end());auto it = st.erase(st.find(id));int t = it == st.begin() ? 0 : a[*prev(it)].l;int q = it == st.end() ? n + 1 : *it;setValue(a[id].l, -1, 1, 1, m);int y = seg2::binary(id, n, t, 1, 1, n);while (y < q) {enable(y);seg2::disable(y);t = a[y].l;y = seg2::binary(id, n, t, 1, 1, n);}}int binary(int L, int R, int v, int p, int l, int r) {if (L <= l && r <= R) {if (maxr[p] <= v) return m + 1;if (l == r) return l;}int mid = (l + r) >> 1;pushdown(p);int ret = L <= mid ? binary(L, R, v, p << 1, l, mid) : m + 1;if (ret <= m) return ret;return mid < R ? binary(L, R, v, p << 1 | 1, mid + 1, r) : m + 1;}void plant(int pos) {debug("plant(pos = %d)\n", pos);// forall range, l <= pos < rint len = hua[pos] - hua[pos - 1]; // hua[], 0-indexedfen.add(pos, len);int res = binary(1, pos, pos, 1, 1, m);if (res <= pos) modify(res, pos, len, 1, 1, m);}int qrymax() { return wh[ans[1].second]; }
};
int main() {
#ifndef LOCAL
#ifndef NFfreopen("ds.in", "r", stdin);freopen("ds.out", "w", stdout);
#endifcin.tie(nullptr)->sync_with_stdio(false);
#endifcin >> n;for (int i = 1; i <= n; i++) cin >> a[i].l >> a[i].r, a[i].id = i, hua << a[i].l << a[i].r;m = (int)hua.build();for (int i = 1; i <= n; i++) a[i].l = (int)hua(a[i].l) + 1;for (int i = 1; i <= n; i++) a[i].r = (int)hua(a[i].r) + 1;auto key = [](auto&& self) { return make_tuple(self.r, -self.l, self.id); };sort(a + 1, a + n + 1, [&](auto&& lhs, auto&& rhs) { return key(lhs) < key(rhs); }); // std::forward /lhfor (int i = 1; i <= n; i++) wh[a[i].id] = i;for (int i = 1; i <= m; i++) nxt[i] = i;seg1::build(1, 1, m);seg2::build(1, 1, n);for (int i = 1; i <= n; i++) {if (st.empty() || a[*st.rbegin()].l < a[i].l) seg1::enable(i);else seg2::enable(i);}for (int t = 1; t <= n; t++) {int pos = seg1::qrymax();cout << a[pos].id << " \n"[t == n];int now = findnxt(a[pos].l);while (now < a[pos].r) {seg1::plant(now);nxt[now] = now + 1;now = findnxt(now);}seg1::disable(pos);
#ifdef LOCALfor (int x : st) debug("%d ", a[x].id);debug("\n");for (int x : st) debug("[%d, %d] ", a[x].l, a[x].r);debug("\n");
#endif}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/809563.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

高级程序语言第二次个人作业

高级程序语言第二次作业这个作业属于哪个课程 https://edu.cnblogs.com/campus/fzu这个作业要求在哪里 https://edu.cnblogs.com/campus/fzu/2024C/homework/13282学号 222200424姓名 赵伟豪编程练习3.13.23.33.43.53.63.73.8示例程序3.13.23.33.43.53.63.73.83.93.10总结与收获…

浏览器的渲染原理

浏览器渲染原理 五个渲染流程Parse 阶段:解析 HTMLStyle 阶段:样式计算三个阶段:收集,划分和索引所有样式表中存在的样式规则 访问每个元素并找到适用于该元素的所有规则,CSS 引擎遍历 DOM 节点,进行选择器匹配,并且匹配的节点执行样式设置 结合层叠规则和其他信息为节点…

CSP2024 前集训:多校A层冲刺NOIP2024模拟赛03

前言T1 没想到正难则反,脑瘫了没敢用 bitset(复杂度擦边但卡常能过),T2 空间开大了挂了 \(100pts\),\(T3\) 是原。 T1 五彩斑斓部分分 \(20pts\):\(O(n^4)\) 暴力。部分分 \(20+?pts\):进行一些优化,极限数据下仍是 \(O(n^4)\)。部分分 \(60\sim 100pts\):bitset 优化…

在C#中使用适配器Adapter模式和扩展方法解决面向的对象设计问题

之前有阵子在业余时间拓展自己的一个游戏框架,结果在实现的过程中发现一个设计问题。这个游戏框架基于MonoGame实现,在MonoGame中,所有的材质渲染(Texture Rendering)都是通过SpriteBatch类来完成的。举个例子,假如希望在屏幕的某个地方显示一个图片材质(imageTexture)…

React Fiber 原理

React Fiber 在 React 16 之前的版本对比更新 VirtualDOM 的过程是采用 Stack 架构实现的,也就是循环加递归,这种方式的问题是一旦任务开始进行就无法被中断。 如果应用中的组件数量庞大, Virtual DOM 的层级比较深,主线程被长期占用,知道整颗 Virtual DOM 树比对更新完成…

视野修炼-技术周刊第104期 | 下一代 JavaScript 工具链

① 🐙 尤大创办公司 VoidZero ② Tauri 2.0 稳定版发布 ③ Vite 时髦的新主页 ④ qrframe - 漂亮二维码生成 ⑤ HTTP QUERY 方法提案 ⑥ TinyJS - 轻量级的创建DOM元素 ⑦ 9月 Web 平台的新功能 ⑧ ESLint 现在正式支持 Linting JSON 和 Markdown欢迎来到第 104 期的【视野修…

雅礼国庆集训 day1 T2 折射

题面 题面下载 算法 转化题意 说白了就是给了你一堆点,让你数这种折线有多少个 (严格向下走,并且横坐标之间的差越来越小)看着像一种在 y 轴方向排序的 dp 但是由于是折线, 所以需要加一维来判断转向 dp 设计 状态设计 \(dp_{i, 0/1}\) 表示第 i 个点, 是向左下还是右上 状态…

React 中的 diff 算法

React diff为什么使用虚拟 DOM ? 浏览器在处理 DOM 的时候会很慢,处理 JavaScript 会很快,页面复杂的时候,频繁操作 DOM 会有很大的性能开销(每次数据变化都会引起整个 DOM 树的重绘和重排)。 为了避免频繁操作 DOM,React 会维护两个虚拟 DOM,如果有数据更新,会借此计…

20222315 2024-2025-1 《网络与系统攻防技术》实验一实验报告

1.实验内容 1.掌握反汇编与十六进制编程器 2.能正确修改机器指令改变程序执行流程 3.能正确构造payload进行bof攻击 2.实验过程 1.直接修改程序机器指令,改变程序执行流程 将pwn1文件下载至kali中并将pwn1文件改名为pwn20222315,并将其内容复制到pwn2反汇编文件objdump -d…

多校A层冲刺NOIP2024模拟赛03

多校A层冲刺NOIP2024模拟赛03\(T1\) A. 五彩斑斓(colorful) \(90/100pts\)部分分\(20pts\) :枚举左上 \((k,h)\) 、右下端点 \((i,j)\) ,时间复杂度为 \(O(n^{2}m^{2})\) 。 \(90/100pts\) :当 \(a_{i,j} \ne a_{k,j}\) 时任意的 \(h \in [1,j]\) 都符合题意、不妨钦定 \(…

Word中 Endnote 引用标蓝色

1. 打开word中的endnote加载项。如图所示,勾选这两个设置。 确认后会自动变为超链接,显示蓝色以及下划线。 2. 在样式设置中,将超链接的下划线取消。之后就会只显示蓝色引用。 结果显示: