P8518 [IOI2021] 分糖果 题解
Description
Khong 阿姨正在给附近一所学校的学生准备
Khong 阿姨花了
-
如果
,Khong 阿姨将糖果一块接一块地放入第 个盒子,直到她正好放了 块糖果或者该盒子已满。也就是说,如果该盒子在这次操作之前已有 块糖果,那么在这次操作之后盒子将有 块糖果。 -
如果
,Khong 阿姨将糖果一块接一块地从第 个盒子取出,直到她正好从盒子中取出 块糖果或者该盒子已空。也就是说,如果该盒子在这次操作之前已有 块糖果,那么在这次操作之后盒子将有 块糖果。
你的任务是求出
约束条件
-
-
-
(对所有 ) -
(对所有 ) -
, (对所有 )
Solution
不妨设
如果取 min 和 max 中只有一种是很好做的,就是这题,但是两个放在一起就不好做了。
容易发现只要找到最小的后缀
考虑如何找到
观察可知如果
时间复杂度:
Code
#include "candies.h" #include <bits/stdc++.h> const int kMaxN = 2e5 + 5; int n, q; int c[kMaxN], l[kMaxN], r[kMaxN], v[kMaxN]; std::vector<std::pair<int, int>> vec[kMaxN]; struct SGT { int64_t mx[kMaxN * 4], mi[kMaxN * 4], posmx[kMaxN * 4], posmi[kMaxN * 4], tag[kMaxN * 4]; void pushup(int x) { if (mx[x << 1] > mx[x << 1 | 1]) { mx[x] = mx[x << 1], posmx[x] = posmx[x << 1]; } else { mx[x] = mx[x << 1 | 1], posmx[x] = posmx[x << 1]; } if (mi[x << 1] < mi[x << 1 | 1]) { mi[x] = mi[x << 1], posmi[x] = posmi[x << 1]; } else { mi[x] = mi[x << 1 | 1], posmi[x] = posmi[x << 1 | 1]; } } void addtag(int x, int64_t v) { tag[x] += v, mx[x] += v, mi[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) { mx[x] = mi[x] = tag[x] = 0, posmx[x] = posmi[x] = r; if (l == r) return; int mid = (l + r) >> 1; build(x << 1, l, mid), build(x << 1 | 1, mid + 1, r); } 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); } int getpos(int x, int l, int r, int64_t nowmx, int64_t nowmi, int64_t v) { if (std::max(nowmx, mx[x]) - std::min(nowmi, mi[x]) < v || l == r) return l; pushdown(x); int mid = (l + r) >> 1; if (std::max(nowmx, mx[x << 1 | 1]) - std::min(nowmi, mi[x << 1 | 1]) >= v) return getpos(x << 1 | 1, mid + 1, r, nowmx, nowmi, v); else return getpos(x << 1, l, mid, std::max(nowmx, mx[x << 1 | 1]), std::min(nowmi, mi[x << 1 | 1]), v); } std::pair<int64_t, int> querymin(int x, int l, int r, int ql, int qr) { if (l > qr || r < ql) return {1e18, -1}; else if (l >= ql && r <= qr) return {mi[x], posmi[x]}; pushdown(x); int mid = (l + r) >> 1; return std::min(querymin(x << 1, l, mid, ql, qr), querymin(x << 1 | 1, mid + 1, r, ql, qr)); } std::pair<int64_t, int> querymax(int x, int l, int r, int ql, int qr) { if (l > qr || r < ql) return {-1e18, -1}; else if (l >= ql && r <= qr) return {mx[x], posmx[x]}; pushdown(x); int mid = (l + r) >> 1; return std::max(querymax(x << 1, l, mid, ql, qr), querymax(x << 1 | 1, mid + 1, r, ql, qr)); } } sgt; std::vector<int> solve() { std::vector<int> ans; for (int i = 1; i <= q; ++i) { vec[l[i]].emplace_back(i, v[i]), vec[r[i] + 1].emplace_back(i, -v[i]); } sgt.build(1, 0, q); for (int i = 1; i <= n; ++i) { for (auto [x, v] : vec[i]) sgt.update(1, 0, q, x, q, v); int p = sgt.getpos(1, 0, q, -1e18, 1e18, c[i]); int64_t sump = sgt.querymin(1, 0, q, p, p).first; if (p && sump == sgt.querymin(1, 0, q, p, q).first) { // 后面只会顶上界 auto [mx, id] = sgt.querymax(1, 0, q, p, q); if (mx - sump <= c[i]) ans.emplace_back(sgt.querymax(1, 0, q, q, q).first - sump); else ans.emplace_back(c[i] - (mx - sgt.querymax(1, 0, q, q, q).first)); } else if (p) { auto [mi, id] = sgt.querymin(1, 0, q, p, q); if (sump - mi <= c[i]) ans.emplace_back(c[i] - (sump - sgt.querymin(1, 0, q, q, q).first)); else ans.emplace_back(sgt.querymin(1, 0, q, q, q).first - mi); } else if (sgt.querymin(1, 0, q, 0, q).first >= 0) { auto [mx, id] = sgt.querymax(1, 0, q, p, q); if (mx <= c[i]) ans.emplace_back(sgt.querymax(1, 0, q, q, q).first); else ans.emplace_back(c[i] - (mx - sgt.querymax(1, 0, q, q, q).first)); } else { auto [mi, id] = sgt.querymin(1, 0, q, p, q); if (mi >= 0) ans.emplace_back(sgt.querymin(1, 0, q, q, q).first); else ans.emplace_back(sgt.querymin(1, 0, q, q, q).first - mi); } } return ans; } std::vector<int> distribute_candies(std::vector<int> c, std::vector<int> l, std::vector<int> r, std::vector<int> v) { n = c.size(), q = l.size(); for (int i = 0; i < n; ++i) ::c[i + 1] = c[i]; for (int i = 0; i < q; ++i) ::l[i + 1] = l[i] + 1, ::r[i + 1] = r[i] + 1, ::v[i + 1] = v[i]; return solve(); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
2023-08-16 CF932E Team Work 题解