【最小生成树+LCA】Imperial roads

http://codeforces.com/gym/101889
I

先跑一遍最小生成树,把经过的边和答案记录下来
对于每个询问的边,显然如果处于MST中,答案不变
如果不在MST中,假设这条边连上了,那么就会和原本的MST形成环,删除这个环中权值最大的边就是答案
处理的时候,可以用LCA维护MST:给出边的两个节点u、v,那么u和v的LCA路径上的最大值边就是环中权值最大的边

代码:

#include <iostream>
#include <cstring>
#include <cmath>
#include <vector>
#include <algorithm>
#include <map>
using namespace std;
typedef long long ll;
const int MAX_V = 100005;
const int MAX_E = 200005;
const int MAX_N = 100005;
struct LCA_Online {
	int N, M, E, root, in[MAX_N], head[MAX_N];
	int f[MAX_N][30], c[MAX_N][30], depth[MAX_N];
	struct Edge {
		int to, next, cost;
	} es[MAX_N << 2];
	void addEdge(int u, int v, int w) {
		es[E].to = v;
		es[E].next = head[u];
		es[E].cost = w;
		head[u] = E++;
		in[v]++;
	}
	void init(int N) {
		this->N = N;
		this->M = floor(log2(double(N)));
		this->E = 0;
		this->root = 0;
		memset(head, -1, sizeof head);
		memset(f, 0, sizeof f);
		memset(c, 0, sizeof c);
		memset(in, 0, sizeof in);
	}
	void dfs(int u) {
		for (int j = 1; j <= M; j++) {
			f[u][j] = f[f[u][j - 1]][j - 1];
			c[u][j] = max(c[u][j - 1], c[f[u][j - 1]][j - 1]);
		}
		for (int i = head[u]; ~i; i = es[i].next) {
			int v = es[i].to;
			int w = es[i].cost;
			if (v != f[u][0]) {
				depth[v] = depth[u] + 1;
				f[v][0] = u;
				c[v][0] = w;
				dfs(v);
			}
		}
	}
	void run() {
		dfs(1);
	}
	int LCA(int u, int v) {
		if (depth[u] < depth[v]) {
			swap(u, v);
		}
		int res = 0;
		int d = depth[u] - depth[v];
		for (int i = 0; i <= M; i++) {
			if ((1 << i) & d) {
				res = max(res, c[u][i]);
				u = f[u][i];
			}
		}
		if (u == v) {
			return res;
		}
		for (int i = M; i >= 0; i--) {
			if (f[u][i] != f[v][i]) {
				res = max(res, max(c[u][i], c[v][i]));
				u = f[u][i];
				v = f[v][i];
			}
		}
		return max(res, max(c[u][0], c[v][0]));
	}
} lca;
struct Kruskal {
	struct Edge {
		int from, to, cost;
		bool operator< (const Edge& e) const {
			return cost < e.cost;
		}
	} es[MAX_E];
	int V, E, p[MAX_V];
	void init(int V) {
		this->V = V;
		this->E = 0;
		for (int i = 0; i < V; i++) {
			p[i] = i;
		}
	}
	void addEdge(int u, int v, int w) {
		es[E].from = u;
		es[E].to = v;
		es[E].cost = w;
		E++;
	}
	int find(int x) {
		return x == p[x] ? x : p[x] = find(p[x]);
	}
	void unite(int x, int y) {
		p[find(y)] = find(x);
	}
	ll kruskal() {
		ll sum = 0;
		sort(es, es + E);
		for (int i = 0; i < E; i++) {
			Edge &e = es[i];
			if (find(e.from) != find(e.to)) {
				sum += e.cost;
				unite(e.from, e.to);
				lca.addEdge(e.from, e.to, e.cost);
				lca.addEdge(e.to, e.from, e.cost);
			}
		}
		return sum;
	}
} kru;
map<pair<int, int>, int> cost;
int main() {
	int N, R, Q;
	scanf("%d%d", &N, &R);
	kru.init(N);
	lca.init(N);
	for (int i = 0, u, v, w; i < R; i++) {
		scanf("%d%d%d", &u, &v, &w);
		if (u > v) {
			swap(u, v);
		}
		cost[make_pair(u, v)] = w;
		//cost[make_pair(v, u)] = w;
		kru.addEdge(u, v, w);
		//kru.addEdge(v, u, w);
	}
	ll ans = kru.kruskal();
	lca.run();
	scanf("%d", &Q);
	while (Q--) {
		int u, v;
		scanf("%d%d", &u, &v);
		if (u > v) {
			swap(u, v);
		}
		printf("%I64d\n", ans + cost[make_pair(u, v)] - lca.LCA(u, v));
	}
}
posted @ 2018-09-03 00:58  Stolf  阅读(336)  评论(0编辑  收藏  举报