P3527 题解

· · 题解

来一篇 O(n\log n) 的题解!

答案具有可二分性,考虑整体二分。设当前分治区间为 [l,r],任务是判断 Q 集合内的国家答案是否小于等于 m=\dfrac{l+r}{2}

还有一个更加暴力的做法:将 $[l,m]$ 操作转化成差分数组上的单点加,然后扫一遍整个序列,也可以求出每个太空站的值。这个做法是可以优化的,因为“关键点”个数只有 $O(\sum\limits_{i\in Q}\lvert S_i\rvert+r-l)$(其中 $S_i$ 表示属于国家 $i$ 的空间站集合),所以如果这些点排好序了,那么就可以直接扫一遍,复杂度优化为 $O(n\log n)$! 考虑在第一次分治之前就排好序,那么在后面的分治中,可以将点集有序地分为两部分,复杂度不会退化。 注意事项: - 计算过程中可能会爆 `long long`。 - 注意有些国家可能没有空间站。 比两只 $\log$ 好写的代码: ```cpp #include <bits/stdc++.h> using namespace std; typedef __int128 _int; #define MAXN 300005 int n, m, q; int a[MAXN], p[MAXN], ans[MAXN]; _int tp[MAXN]; struct Node{int x, k, id;}; vector<Node> Q; void sol(int l, int r, vector<Node> Q){ if (l == r){for (auto i: Q) if (!i.k) ans[a[i.x]]=l; return;} int mid((l+r)>>1); for (_int i(0), res(0); i<Q.size(); ++i){ if (!Q[i].k) tp[a[Q[i].x]] += res; else if (Q[i].id <= mid) res += Q[i].k; } vector<Node> ql, qr; for (auto i: Q){ if (i.k) (i.id <= mid ? ql : qr).push_back(i); else if (tp[a[i.x]] >= p[a[i.x]]) ql.push_back(i); else p[a[i.x]] -= tp[a[i.x]], tp[a[i.x]] = 0, qr.push_back(i); } for (auto i: Q) tp[a[i.x]] = 0; sol(l, mid, ql); sol(mid+1, r, qr); } signed main(){ ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin >> m >> n; for (int i(1); i<=n; ++i) cin >> a[i], Q.push_back({i, 0, 0}); for (int i(1); i<=m; ++i) cin >> p[i]; cin >> q; for (int i(1), l, r, k; i<=q; ++i){ cin >> l >> r >> k; if (l <= r) Q.push_back({l, k, i}), Q.push_back({r+1, -k, i}); else Q.push_back({1, k, i}), Q.push_back({r+1, -k, i}), Q.push_back({l, k, i}); } sort(Q.begin(), Q.end(), [](Node a, Node b){return a.x == b.x ? !a.k < !b.k : a.x < b.x;}); memset(ans, 0x3f, sizeof(ans)); sol(1, q+1, Q); for (int i(1); i<=m; ++i) if (ans[i] > q) cout << "NIE\n"; else cout << ans[i] << '\n'; return 0; } ```