1 条题解
-
0
比较简单?
考虑一个询问本质上只是将 里面的点缩起来然后再求 mst。
注意到我们考虑建出克鲁斯卡尔重构树,那么只需要考虑删去 的 LCA 对应的贡献。
然后这个就是典了,考虑支配对,我们进行 dsu on tree,然后每次考虑加入跨过子树的一对前驱和后驱 ,一共 组。
然后这个 的贡献视作二维平面上的点,转化为 2-side 矩形求颜色并,这个非常 Easy 啊,扫描线即可。
复杂度 。
#include <bits/stdc++.h> #define rep(i, l, r) for (int i = l; i <= r; i ++) #define per(i, r, l) for (int i = r; i >= l; i --) #define int long long /* 使い切って声に出そう 单点加,区间查询。 */ using namespace std; typedef long long ll; const int _ = 3e5 + 5, mod = 998244353; int read() { int x = 0, f = 1; char ch = getchar(); while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = getchar(); } return x * f; } int tn, n, m, q, sum; int bits[_]; void add (int x, int k) { if (!x) return ; for ( ; x <= n; x += x & -x) bits[x] += k; } int query (int x) { int ret = 0; for ( ; x; x -= x & -x) ret += bits[x]; return ret; } vector<int> e[_]; int v[_], sz[_], son[_]; struct edge { int x, y, z; }; vector<edge> g; vector<pair<int, int> > cv[_], qv[_]; int anc[_], col[_], ans[_]; int dfn[_], ed[_], dfc, id[_]; int find (int x) { return x == anc[x] ? x : anc[x] = find(anc[x]); } set <int> s; signed main () { tn = n = read(), m = read(), q = read(); rep(i, 1, n + n) anc[i] = i; rep(i, 1, m) { int x = read() + 1, y = read() + 1, z = read(); g.push_back({x, y, z}); } auto kruskal = [&]() -> void { sort(g.begin(), g.end(), [&](edge u, edge v) { return u.z < v.z; } ); for (auto [x, y, z] : g) { x = find(x), y = find(y); if (x != y) { ++ tn; anc[x] = anc[y] = tn; sum += z, v[tn] = z; e[tn].push_back(x), e[tn].push_back(y); } } } ; auto pre_dfs = [&](auto &self, int x) -> void { dfn[x] = ++ dfc; id[dfc] = x; sz[x] = 1; for (int y : e[x]) { self(self, y); sz[x] += sz[y]; if (sz[y] > sz[son[x]]) son[x] = y; } ed[x] = dfc; } ; auto ins = [&](int x, int lca) -> void { auto it = s.lower_bound(x); if (it != s.end()) cv[*it].push_back({x, lca}); if (it != s.begin()) cv[x].push_back({*prev(it), lca}); } ; auto dsu = [&](auto &self, int x, int ty) -> void { for (int y : e[x]) if (y ^ son[x]) self(self, y, 0); if (son[x]) self(self, son[x], 1); for (int y : e[x]) { if (y == son[x]) continue ; rep(i, dfn[y], ed[y]) ins(id[i], x); rep(i, dfn[y], ed[y]) s.insert(id[i]); } if (!ty) rep(i, dfn[x], ed[x]) s.erase(id[i]); else if (x <= n) s.insert(x); } ; kruskal(); pre_dfs(pre_dfs, tn); dsu(dsu, tn, 0); rep(i, 1, q) { int l = read() + 1, r = read() + 1; qv[r].push_back({l, i}); } rep(r, 1, n) { for (auto [l, c] : cv[r]) if (l > col[c]) { add(col[c], -v[c]); col[c] = l; add(col[c], v[c]); } for (auto [l, id] : qv[r]) ans[id] = query(r) - query(l - 1); } rep(i, 1, q) printf("%lld\n", sum - ans[i]); return 0; }
- 1
信息
- ID
- 10185
- 时间
- 4000ms
- 内存
- 1024MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者