rt,MLE 到想似。。。做法是线段树分治 + LCT,经检验答案是对的,单纯是空间太大了
代码特别可读
#include <bits/stdc++.h>
using namespace std;
#define rep(i, j, k) for (int i = (j); i <= (k); ++i)
#define reo(i, j, k) for (int i = (j); i >= (k); --i)
typedef long long ll;
const int N = 20010, M = 50010, P = 1e5 + 10;
array<int, 3> edges[M];
int n, m, q;
namespace LinkCutTree {
int fa[P], ch[P][2], rev[P], mxid[P], val[P], mx[P], left[P];
ll sum = 0;
#define get(u) (u == ch[fa[u]][1])
#define nrt(u) (u == ch[fa[u]][0] || u == ch[fa[u]][1])
void up(int u) {
mx[u] = max({mx[ch[u][0]], mx[ch[u][1]], val[u]});
if (mx[u] == mx[ch[u][0]]) mxid[u] = mxid[ch[u][0]];
else if (mx[u] == mx[ch[u][1]]) mxid[u] = mxid[ch[u][1]];
else mxid[u] = u;
if (ch[u][0]) left[u] = left[ch[u][0]];
else left[u] = u;
}
void Rev(int u) { if (u) rev[u] ^= 1, swap(ch[u][0], ch[u][1]), left[u] = ch[u][0] ? left[ch[u][0]] : u; }
void down(int u) { if (rev[u]) Rev(ch[u][0]), Rev(ch[u][1]), rev[u] = 0; }
void Down(int u) { if (nrt(u)) Down(fa[u]); down(u); }
void rot(int u) {
int f = fa[u], g = fa[f], k = get(u);
if (nrt(f)) ch[g][get(f)] = u;
ch[f][k] = ch[u][!k];
if (ch[u][!k]) fa[ch[u][!k]] = f;
ch[u][!k] = f, fa[f] = u, fa[u] = g, up(f), up(u);
}
void splay(int u) { for (Down(u); nrt(u); rot(u)) if (nrt(fa[u])) rot(get(u) == get(fa[u]) ? fa[u] : u); }
void access(int u) { for (int v = 0; u; v = u, u = fa[u]) splay(u), ch[u][1] = v, up(u); }
void makert(int u) { access(u), splay(u), Rev(u); }
int find(int u) { return access(u), splay(u), left[u]; }
void link(int u, int v) { makert(u), splay(v), fa[u] = v; }
void cut(int u, int v) { makert(u), access(v), splay(v), ch[v][0] = fa[u] = 0, up(v); }
void split(int u, int v) { makert(u), access(v), splay(v); }
#undef get
#undef nrt
}
#define mid ((l + r) >> 1)
vector<array<int, 3>> Edges[M << 2], All;
void Ins(int u, int l, int r, int x, int y, array<int, 3> edge) {
if (y < l || r < x || x > y) return;
if (x <= l && r <= y) return (void)(Edges[u].push_back(edge));
Ins(u << 1, l, mid, x, y, edge), Ins((u << 1) | 1, mid + 1, r, x, y, edge);
}
int tot;
void Solve(int now, int l, int r) {
using namespace LinkCutTree;
vector<array<int, 3>> vec;
ll Originsum = sum;
for (auto edge : Edges[now]) {
int u = edge[0], v = edge[1], w = edge[2];
++tot, mxid[tot] = LinkCutTree::left[tot] = tot, val[tot] = mx[tot] = w, All.push_back(edge);
if (find(u) != find(v)) {
link(u, tot), link(tot, v), sum += w;
vec.push_back({1, u, tot}), vec.push_back({1, tot, v});
} else {
split(u, v);
if (mx[v] > w) {
int id = mxid[v], x = All[id - n - 1][0], y = All[id - n - 1][1];
cut(x, id), cut(id, y);
link(u, tot), link(tot, v);
sum -= All[id - n - 1][2], sum += w;
vec.push_back({0, x, id}), vec.push_back({0, id, y});
vec.push_back({1, u, tot}), vec.push_back({1, tot, v});
}
}
}
if (l == r) {
cout << sum << '\n';
} else {
Solve(now << 1, l, mid), Solve((now << 1) | 1, mid + 1, r);
}
sum = Originsum;
for (auto it : vec)
if (it[0] == 1)
cut(it[1], it[2]);
for (auto it : vec)
if (it[0] == 0)
link(it[1], it[2]);
}
#undef mid
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
cin >> n >> m >> q;
vector<int> last(m + 1, 1);
rep(i, 1, m) {
cin >> edges[i][0] >> edges[i][1] >> edges[i][2];
}
rep(i, 1, q) {
int k, d;
cin >> k >> d;
Ins(1, 1, q, last[k], i - 1, edges[k]);
edges[k][2] = d;
last[k] = i;
}
tot = n;
rep(i, 1, m) Ins(1, 1, q, last[i], q, edges[i]);
Solve(1, 1, q);
return 0;
}