bzoj4383 [POI2015]Pustynia 拓扑排序+差分约束+线段树优化建图
题目传送门
https://lydsy.com/JudgeOnline/problem.php?id=4383
题解
暴力的做法显然是把所有的条件拆分以后暴力建一条有向边表示小于关系。
因为不存在零环,所以随后可以用拓扑排序来解决。
考虑如何优化。
第一个优化比较显而易见,对于一个条件,新建一个虚点,连向所有给出的点。
第二个是,我们可以发现,给定这 \(k\) 个点以后,实际上需要建的边是从最多 \(k + 1\) 个区间中引出的,所以可以考虑线段树优化建图。
然后就可以和上面一样的,因为不存在零环,所以随后可以用拓扑排序来解决。
然后这样的时间复杂度是 \(O((m+\sum k)\log n)\)。
这似乎是我第一次写线段树优化建图呢~虽然一年前就已经学过了,但是一直没写过。
#include<bits/stdc++.h> #define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to) #define dbg(...) fprintf(stderr, __VA_ARGS__) #define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout) #define fi first #define se second #define pb push_back template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b, 1 : 0;} template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b, 1 : 0;} typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii; template<typename I> inline void read(I &x) { int f = 0, c; while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0; x = c & 15; while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15); f ? x = -x : 0; } const int N = 100000 * 6 + 7; const int M = 100000 * (4 + 3 + 17 + 17) + 7; #define lc o << 1 #define rc o << 1 | 1 int n, ns, m, nod; int dp[N], nd[N], idg[N], pre[N], rel[N], tmp[N], q[N]; struct Edge { int to, ne, w; } g[M]; int head[N], tot; inline void addedge(int x, int y, int z) { g[++tot].to = y, g[tot].w = z, g[tot].ne = head[x], head[x] = tot; } inline void adde(int x, int y, int z) { addedge(x, y, z), addedge(y, x, z); } inline void add_e(int x, int y, int z) { ++idg[y], addedge(x, y, z); } inline void build(int o, int L, int R) { if (L == R) return (void)(rel[L] = o, pre[o] = L); int M = (L + R) >> 1; add_e(lc, o, 0), build(lc, L, M); add_e(rc, o, 0), build(rc, M + 1, R); } inline void addi(int o, int L, int R, int l, int r, int x) { // dbg("o = %d, L = %d, R = %d, l = %d, r = %d, x = %d\n", o, L, R, l, r, x); if (l <= L && R <= r) return add_e(o, x, 1); int M = (L + R) >> 1; if (l <= M) addi(lc, L, M, l, r, x); if (r > M) addi(rc, M + 1, R, l, r, x); } inline void work() { int hd = 0, tl = 0; for (int i = 1; i <= nod; ++i) if (idg[i] == 0) q[++tl] = i, smax(dp[i], 1); while (hd < tl) { int x = q[++hd]; // if (dp[x] >= n) dbg("******* x = %d, dp[x] = %d, nd[x] = %d\n", x, dp[x], nd[x]); if (nd[x]) { if (dp[x] > nd[x]) { puts("NIE"); return; } else dp[x] = nd[x]; } for fec(i, x, y) { smax(dp[y], dp[x] + g[i].w); if (!--idg[y]) q[++tl] = y; } } for (int i = 1; i <= n; ++i) if (!dp[rel[i]] || dp[rel[i]] > 1e9) { puts("NIE"); return; } puts("TAK"); for (int i = 1; i <= n; ++i) printf("%d%c", dp[rel[i]], " \n"[i == n]); } inline void init() { read(n), read(ns), read(m); int x, y; build(1, 1, n); nod = n << 2; for (int i = 1; i <= ns; ++i) read(x), read(y), dp[rel[x]] = nd[rel[x]] = y; for (int i = 1; i <= m; ++i) { int l, r, k; read(l), read(r), read(k); ++nod; for (int i = 1; i <= k; ++i) { read(tmp[i]); add_e(nod, rel[tmp[i]], 0); if (i == 1) tmp[i] > l ? addi(1, 1, n, l, tmp[i] - 1, nod) : (void)0; else tmp[i] - tmp[i - 1] > 1 ? addi(1, 1, n, tmp[i - 1] + 1, tmp[i] - 1, nod) : (void)0; } if (tmp[k] != r) addi(1, 1, n, tmp[k] + 1, r, nod); } } int main() { #ifdef hzhkk freopen("hkk.in", "r", stdin); #endif init(); work(); fclose(stdin), fclose(stdout); return 0; }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· DeepSeek火爆全网,官网宕机?本地部署一个随便玩「LLM探索」
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 上周热点回顾(1.20-1.26)
· 【译】.NET 升级助手现在支持升级到集中式包管理
2018-10-31 [校内NOIP2017模拟20171029] 不可逆的重启动
2018-10-31 [校内NOIP2018模拟20181031] 西行妖下
2018-10-31 [校内NOIP2018模拟20181031] 式神守护
2018-10-31 [校内NOIP2018模拟20181031] 白玉楼前