ABC314G Amulets
提供一个常数巨大的暴力数据结构做法。
分析
看到这种极值类问题,可以先想一想二分。由于这题中可以击败的怪物一定是一段连续的前缀,所以考虑二分这段前缀的长度。
由于本题中一道护身符免掉的是一种类型的怪物所造成的总伤害,所以考虑单个怪物的伤害是没有意义的。接下来我们只考虑某一区间中同一类型的怪物所造成的总伤害。
那么二分之后考虑如何判断可行性。显然根据贪心的原则,我们一定会优先考虑免掉 造成最多伤害的 怪物类型 所造成的 总伤害。也就是说,对于一段前缀,我们每次去询问出现在这段前缀中的 每种类型的怪物 造成的总伤害 的前
以下所说的前
直接讲可能不太好讲,所以我们先从权值线段树讲起。这题用到的权值线段树的本质上是一个桶,但是这个桶可以查询前
接下来考虑如何维护主席树。显然,加入一个怪物时,其所属的类型的怪物的总伤害会增加,对于桶来说就是原本的值少了一个,加上后得到的值多了一个。那么到线段树上就是先删掉原本的值,再加上现在的值。这样我们就可以得到一棵前缀线段树 (可持久化桶)。其中每个
那么这样就有了一棵前缀线段树。对于每一个
总时间复杂度
代码
#pragma GCC optimize(2)
#include <iostream>
#include <set>
#define ll long long
using namespace std;
const ll N = 3e14;
int n, m, h;
int a[300005], b[300005];
int ptcnt[300005];
ll msum[300005];
int rt[600005];
ll S[300005];
set<int> st;
struct Persistent_Segment_Tree {
struct node {
int l, r, sm;
ll smv;
} T[31000005];
int ncnt;
void Build(int& o, ll l, ll r) noexcept {
o = ++ncnt;
T[o].sm += m;
if (l == r)
return;
Build(T[o].l, l, (l + r) >> 1);
}
void Insert(int p, int& q, ll l, ll r, ll x, int y) noexcept {
q = ++ncnt;
T[q] = T[p];
T[q].sm += y;
T[q].smv += y * x;
if (l == r)
return;
ll mid = (l + r) >> 1;
(x <= mid) ? Insert(T[p].l, T[q].l, l, mid, x, y) : Insert(T[p].r, T[q].r, mid + 1, r, x, y);
}
ll Query(int o, ll l, ll r, int k) noexcept {
if (!o)
return 0;
if (l == r)
return l * k;
ll mid = (l + r) >> 1;
return (T[T[o].r].sm >= k) ? Query(T[o].r, mid + 1, r, k) : (T[T[o].r].smv + Query(T[o].l, l, mid, k - T[T[o].r].sm));
}
} seg;
inline bool chk(int c, int k) noexcept {
if (ptcnt[k] <= c)
return 1;
ll tmp = seg.Query(rt[k], 0, N, c);
ll dt = S[k] - tmp;
return (dt < h);
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m >> h;
seg.Build(rt[0], 0, N);
for (int i = 1; i <= n; i++) {
cin >> a[i] >> b[i];
S[i] = S[i - 1] + a[i];
st.insert(b[i]);
ptcnt[i] = st.size();
seg.Insert(rt[i - 1], rt[i + n], 0, N, msum[b[i]], -1);
msum[b[i]] += a[i];
seg.Insert(rt[i + n], rt[i], 0, N, msum[b[i]], 1);
}
for (int i = 0; i <= m; i++) {
int l = 0, r = n, ans = 0, mid;
while (l <= r) {
mid = (l + r) >> 1;
if (chk(i, mid))
ans = mid, l = mid + 1;
else
r = mid - 1;
}
cout << ans << " ";
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?