QOJ10042 Scheduling 题解

news/2025/4/1 3:52:26/文章来源:https://www.cnblogs.com/Scarab/p/18799504

Description

给定 \(n\) 个二元组 \((l_i,r_i)\),请你构造一个长度为 \(n\) 的序列 \(a\),满足:

  • \(\forall 1\le i\le n\)\(l_i\le a_i\le r_i\)
  • \(\forall 1\le i<j\le n\)\(|a_i-a_j|\ge2\)

\(T\) 组数据。

\(1\le T\le 100,1\le \sum n\le 2\times 10^5,1\le l_i\le r_i\le 10^6\)

Solution

首先如果只要求互不相同就是个经典的贪心,对区间按照 \(r\) 排序,每次选择 \(\geq l_i\) 的最小的数选。

但是这里显然不能这么做。考虑通过构造候选集合,来转化成上面的那个贪心。

即构造一个序列 \(b_1,b_2,\ldots,b_m\),满足 \(\forall 1\leq i<j\leq m,|b_i-b_j|\geq 2\) 且满足最终的答案都在这里面选。

注意到如果给定 \(b\) 序列,这就是个单点匹配区间的问题,可以用 Hall 定理判断有无解。

所以考虑 Hall 定理。

\(F(l,r)\) 表示包含于 \([l,r]\) 的询问区间数,\(G(l,r)=r-l+1-2\cdot F(l,r)\),可以用线段树+扫描线维护 \(G(l,r)\) 的值。

那么如果存在 \(l,r\),使得 \(G(l,r)\leq -2\),那么无论怎么填都不能满足这个区间的限制,也就是无解。

如果 \(G(l,r)=-1\),那么这个区间一定是填形如 \(1010101\) 这样一个 \(1\) 一个 \(0\) 交错的形式。

其余的先不管。

把所有满足 \(G(l,r)=-1\) 的区间拿出来后,已经可以确定一部分位置的答案了,把这些已知的为 \(1\) 的位置 \(c_1,c_2,\ldots,c_k\) 拿出来后容易发现不同区间之间的填法基本上是独立的,考虑从前往后对于 \([c_i+1,c_{i+1}-1]\) 分别做。

如果 \((c_{i+1}-c_i)\bmod 2=0\),那么这个区间一定填的是 \(010101\ldots 010\),其余的一定不优。

如果 \((c_{i+1}-c_i)\bmod 2=1\),注意到现在不能像上面那样去完全交错填了,即一定存在一个 \(g\),满足 \(g\)\(g+1\) 都是 \(0\),可以发现 \([c_i,g-1]\)\([g+2,c_{i+1}]\) 都交错着填一定更优。

由于 \(g\) 越小对于后面的区间一定更优,所以只需要对于当前区间找到最小的能够满足所有 \(r\leq c_{i+1}\) 的区间的限制的 \(g\) 即可。

\(H(l,r)\) 表示 \([l,r] 没有确定答案的点数+2\times \left([l,r] 中确定的 1 的个数-包含于 [l,r] 的区间数\right)\),容易发现所有没有确定的点一定都在 \((c_i,c_{i+1})\) 内。

考虑从前往后扫右端点 \(r\),找到满足 \(H(l,r)\) 最小的最小的 \(l\)

  • 如果 \(H(l,r)<0\),显然 \(l\leq c_i\),否则 \(l\) 一定会被加到 \(c\) 数组里。由于 \(c_i+1\) 一定填 \(0\),所以无论如何也不能满足 \([l,r]\) 的限制。

  • 如果 \(H(l,r)=0\),则 \(g\)\(g+1\) 出现在 \([l,r]\) 里会让 \(H(l,r)\) 减为负数,不满足条件,给 \([l,r]\) 打上标记表示 \(g\) 不能出现在里面。

  • 如果 \(H(l,r)>0\),则 \(g\) 在哪里 \([l,r]\) 都能满足条件,不管它。

最后 \((c_i,c_{i+1})\) 里找最小的与 \(c_{i+1}\) 奇偶性相同且没被打上标记的位置就是 \(g\),然后更新线段树。


注意多组数据 \(\sum r_i\) 是没有限制的,所以需要离散化。具体的做法是按照 \(l\) 排序,然后每次找到 \(\geq l_i\)\(3\) 没选的位置加进去,最后对 \(l,r\) 分别二分找到对应取值,再做上面的东西。

时间复杂度:\(O(n\log n)\)

Code

#include <bits/stdc++.h>// #define int int64_tusing pii = std::pair<int, int>;const int kMaxN = 6e5 + 5;int n, m, cnt;
int a[kMaxN], res[kMaxN], l[kMaxN], r[kMaxN], unq[kMaxN];
std::vector<int> vv[kMaxN];struct SGT {pii mi[kMaxN * 4];int tag[kMaxN * 4];void pushup(int x) {mi[x] = std::min(mi[x << 1], mi[x << 1 | 1]);}void addtag(int x, int v) {mi[x].first += v, tag[x] += v;}void pushdown(int x) {if (tag[x]) {addtag(x << 1, tag[x]), addtag(x << 1 | 1, tag[x]);tag[x] = 0;}}void build(int x, int l, int r) {tag[x] = 0;if (l == r) return void(mi[x] = {0, l});int mid = (l + r) >> 1;build(x << 1, l, mid), build(x << 1 | 1, mid + 1, r);pushup(x);}void update(int x, int l, int r, int ql, int qr, int v) {if (l > qr || r < ql) return;else if (l >= ql && r <= qr) return addtag(x, v);pushdown(x);int mid = (l + r) >> 1;update(x << 1, l, mid, ql, qr, v), update(x << 1 | 1, mid + 1, r, ql, qr, v);pushup(x);}pii query(int x, int l, int r, int ql, int qr) {if (l > qr || r < ql) return {1e9, 0};else if (l >= ql && r <= qr) return mi[x];pushdown(x);int mid = (l + r) >> 1;return std::min(query(x << 1, l, mid, ql, qr), query(x << 1 | 1, mid + 1, r, ql, qr));}
} sgt;void discrete() {std::vector<int> vec;for (int i = 1; i <= n; ++i) vec.emplace_back(l[i]);std::sort(vec.begin(), vec.end());int p = 0;m = 0;for (auto x : vec) {for (int i = 1; i <= 3; ++i) {unq[++m] = p = std::max(p + 1, x);}}for (int i = 1; i <= m; ++i) std::vector<int>().swap(vv[i]);for (int i = 1; i <= n; ++i) {l[i] = std::lower_bound(unq + 1, unq + 1 + m, l[i]) - unq;r[i] = std::lower_bound(unq + 1, unq + 1 + m, r[i]) - unq - 1;vv[r[i]].emplace_back(l[i]);}
}bool getarr() {static int diff[kMaxN][2];cnt = 0, sgt.build(1, 1, m);for (int i = 0; i <= m; ++i) diff[i][0] = diff[i][1] = 0;for (int i = 1; i <= m; ++i) {sgt.update(1, 1, m, 1, i, 1);for (auto x : vv[i]) sgt.update(1, 1, m, 1, x, -2);auto p = sgt.query(1, 1, m, 1, i);if (p.first < -1) return 0;if (p.first == -1) {int j = p.second;++diff[j][1], --diff[i + 2][1];++diff[j + 1][0], --diff[i + 1][0];}}for (int i = 1; i <= m; ++i) {if (i >= 2) diff[i][0] += diff[i - 2][0], diff[i][1] += diff[i - 2][1];if (diff[i][0] && diff[i][1]) return 0;if (diff[i][1]) a[++cnt] = i;}int lst = cnt;sgt.build(1, 1, m);if (!cnt) {for (int i = 1; i <= m; i += 2) a[++cnt] = i;return 1;}for (int i = 1; i <= a[1]; ++i) {for (auto x : vv[i]) sgt.update(1, 1, m, 1, x, -2);if (i < a[1] && i % 2 == a[1] % 2)a[++cnt] = i, sgt.update(1, 1, m, 1, i, 2);}sgt.update(1, 1, m, 1, a[1], 2);for (int i = 1; i < lst; ++i) {int p = a[i], q = a[i + 1];if (q - p <= 1) return 0;if (p % 2 == q % 2) {for (int j = p + 2; j < q; j += 2)a[++cnt] = j, sgt.update(1, 1, m, 1, j, 2);for (int j = p + 1; j <= q; ++j)for (auto x : vv[j])sgt.update(1, 1, m, 1, x, -2);sgt.update(1, 1, m, 1, q, 2);} else {static int tmp[kMaxN];for (int j = p; j <= q; ++j) tmp[j] = 0;for (int j = p + 1; j <= q; ++j) {sgt.update(1, 1, m, 1, j, 1 + (j == q));for (auto x : vv[j]) sgt.update(1, 1, m, 1, x, -2);auto p = sgt.query(1, 1, m, 1, j);if (p.first < 0) return 0;if (p.first == 0) {++tmp[std::max(p.second, a[i])], --tmp[j];}}for (int j = p + 1; j <= q; ++j) tmp[j] += tmp[j - 1];int gap = -1;for (int j = p + 1; j < q; ++j) {if (j % 2 != p % 2 && !tmp[j]) { gap = j; break; }}if (!~gap) return 0;for (int j = p + 1; j <= q; ++j) sgt.update(1, 1, m, 1, j, -(1 + (j == q)));for (int j = p + 2; j < gap; j += 2)a[++cnt] = j, sgt.update(1, 1, m, 1, j, 2);for (int j = gap + 2; j < q; j += 2)a[++cnt] = j, sgt.update(1, 1, m, 1, j, 2);sgt.update(1, 1, m, 1, q, 2);}}for (int i = a[lst] + 2; i <= m; i += 2) a[++cnt] = i;std::sort(a + 1, a + 1 + cnt);return 1;
}bool getres() {std::vector<int> vec;for (int i = 1; i <= n; ++i) vec.emplace_back(i);std::sort(vec.begin(), vec.end(), [&] (int x, int y) { return r[x] < r[y] || r[x] == r[y] && l[x] > l[y]; });std::set<int> st;for (int i = 1; i <= cnt; ++i) st.emplace(a[i]);for (auto i : vec) {auto it = st.lower_bound(l[i]);if (it != st.end() && *it <= r[i]) {res[i] = *it, st.erase(it);} else {return 0;}}return 1;
}void dickdreamer() {std::cin >> n;for (int i = 1; i <= n; ++i) std::cin >> l[i] >> r[i];discrete();if (!getarr() || !getres()) return void(std::cout << "-1\n");for (int i = 1; i <= n; ++i) std::cout << unq[res[i]] << " \n"[i == n];
}int32_t main() {
#ifdef ORZXKRfreopen("in.txt", "r", stdin);freopen("out.txt", "w", stdout);
#endifstd::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);int T = 1;std::cin >> T;while (T--) dickdreamer();// std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";return 0;
}

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

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

相关文章

[DevOps] 使用 Windows Sysprep(系统准备)重置计算机 SID

关于 Sysprep(系统准备) https://learn.microsoft.com/zh-cn/windows-hardware/manufacture/desktop/sysprep--system-preparation--overview?view=windows-11 Sysprep 是 Windows 映像的一部分,在审核模式下运行。Sysprep(系统准备)可以准备 Windows 客户端或 Windows S…

堆区的介绍

悲观者从机会中看到困难。乐观者从困难中看到机会。 ——温斯顿丘吉尔我们先来说堆。堆是 OOM 故障最主要的发生区域。它是内存区域中最大的一块区域,被所有线程共享,存储着几乎所有的实例对象、数组。所有的对象实例以及数组都要在堆上分配,但是随着 JIT 编译器的发展与逃逸…

langchain0.3教程:从0到1打造一个智能聊天机器人

构建一个智能对话聊天机器人需要多少行代码?只需要不到30行。本篇文章结合gradio和langchain0.3从0到1创建一个智能聊天机器人并逐步优化流式输出、上下文记忆等功能在上一篇文章《大模型开发之langchain0.3(一):入门篇》 中已经介绍了langchain开发框架的搭建,最后使用la…

OpenGL渲染YUV实战:GPU加速转换与MipMap模糊效果实现

本文介绍了使用Qt和OpenGL渲染YUV420P数据的方法,包括YUV到RGB的转换以及通过OpenGL实现画质模糊的技术。文章详细讲解了YUV420P的结构、OpenGL纹理处理、MipMap技术及其在模糊效果中的应用,并探讨了在OpenGL ES 2.0环境下的兼容性问题及解决方案。最后,提出了进一步优化性能…

OpenGL绘制YUV、OpenGL 实现画质模糊以及 OpenGL ES 实现画质模糊

本文介绍了使用Qt和OpenGL渲染YUV420P数据的方法,包括YUV到RGB的转换以及通过OpenGL实现画质模糊的技术。文章详细讲解了YUV420P的结构、OpenGL纹理处理、MipMap技术及其在模糊效果中的应用,并探讨了在OpenGL ES 2.0环境下的兼容性问题及解决方案。最后,提出了进一步优化性能…

electron浏览器模式多标签方案

main.js let mainWindow function createWindow () {// Create the browser window.mainWindow = new BrowserWindow({}) }app.whenReady().then(() => {createWindow()const tabManager = new TabManager(mainWindow, baseUrl);//打开标签ipcMain.handle(open-tab, (event,…

EtherNet/IP转ProfiNet协议转换网关实现Alicat流量计数据批量接入西门子TIA Portal系统

一、案例背景 汽车涂装线的静电喷涂工艺对压缩空气流量稳定性要求极高。原系统中Alicat流量计与西门子PLC因协议差异无法联动,导致涂料浪费率高达8%。通过JM-EIPM-PN网关实现供气系统与PLC的深度集成。从而实现了EtherNet/IP转ProfiNet的通讯。二、设备连接与配置 设备配置: …

Ethernet/IP转Modbus助力库卡机器人与S7-1200PLC高效双向通讯

项目背景 在某汽车零部件生产车间的焊接生产线中,使用了库卡机器人进行焊接操作,其控制系统采用 Ethernet/IP 协议。同时,车间的自动化控制系统以西门子 S7 - 1200 PLC 为核心,采用 Modbus TCP 协议进行数据交互。为了实现焊接过程的自动化控制和生产数据的实时监控,需要将…

泛型--java进阶day10

1.泛型2.泛型--统一数据类型 如下图,当我们在泛型中添加不同的数据类型,add方法需要的数据类型也随之改变 [1][2]泛型--默认类型object当我们不指定泛型时,泛型的默认类型为object,所以add方法可以存储任意数据类型3.泛型--将运行期间错误提升到编译期 如下图,我们在集合中…

web139笔记(过if和sleep来判断盲注)

<?php error_reporting(0); function check($x){if(preg_match(/\\$|\.|\!|\@|\#|\%|\^|\&|\*|\?|\{|\}|\>|\<|nc|wget|exec|bash|sh|netcat|grep|base64|rev|curl|wget|gcc|php|python|pingtouch|mv|mkdir|cp/i, $x)){die(too young too simple sometimes naiv…

App性能测试工具-solopi

Solopi 简介Solopi 是阿里的一款开源的APP测试工具,能对App进行UI自动化测试和性能测试,而且还能进行单台设备控制多台测试设备 的工具。在使用Solopi 时不用进行root权限,但需要连接到adb(android SDK提供的命令行工具)。因此在使用Solopi之前需要开启开发者权限。 Solop…