求卡空间
查看原帖
求卡空间
381617
LaiJinYi楼主2024/9/25 20:04

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;
}
2024/9/25 20:04
加载中...