洛谷 P4949 最短距离

基环树,断掉一条不影响联通性的边 \((u, v, w)\) 然后树剖。

\[ans_{i, j} = \min\{dist_{i, j}, dist_{i, u} + w + dist_{v, j}, dist_{i, v} + w + dist_{u, j}\} \]

#include <cstdio>

const int MAXN = 1e5 + 19;

typedef long long ll;

class Tarr{
	private:
		int n;
		ll tr[MAXN];
		ll q(int x){
			ll res = 0;
			for(; x; x -= x & -x)
				res += tr[x];
			return res;
		}
	public:
		void set(int size){
			n = size;
		}
		void update(int x, int k){
			for(; x <= n; x += x & -x)
				tr[x] += k;
		}
		ll query(int l, int r){
			return q(r) - q(l - 1);
		}
}myTree;

struct Edge{
	int to, next, dist;
}edge[MAXN << 1];

int cnt, head[MAXN];

inline void add(int from, int to, int dist){
	edge[++cnt].to = to;
	edge[cnt].dist = dist;
	edge[cnt].next = head[from];
	head[from] = cnt;
}

int n, q;

int ind;
int fa[MAXN], son[MAXN], dfn[MAXN], size[MAXN], dep[MAXN], top[MAXN];

int s1, s2, sd;

int weight[MAXN];

void dfs1(int node, int f){
	dep[node] = dep[f] + 1, fa[node] = f, size[node] = 1;
	int max = 0;
	for(int i = head[node]; i; i = edge[i].next)
		if(edge[i].to != f){
			dfs1(edge[i].to, node);
			size[node] += size[edge[i].to];
			if(size[edge[i].to] > max)
				max = size[edge[i].to], son[node] = edge[i].to;
			weight[edge[i].to] = edge[i].dist;
		}
}

void dfs2(int node, int f, int t){
	dfn[node] = ++ind, top[node] = t;
	if(son[node])
		dfs2(son[node], node, t);
	for(int i = head[node]; i; i = edge[i].next)
		if(edge[i].to != f && edge[i].to != son[node])
			dfs2(edge[i].to, node, edge[i].to);
}

int queryPath(int x, int y){
	int res = 0;
	while(top[x] != top[y]){
		if(dep[top[x]] > dep[top[y]])
			res += myTree.query(dfn[top[x]], dfn[x]), x = fa[top[x]];
		else
			res += myTree.query(dfn[top[y]], dfn[y]), y = fa[top[y]];
	}
	int lca = dep[x] < dep[y] ? x : y;
	if(dep[x] < dep[y])
		res += myTree.query(dfn[x], dfn[y]);
	else
		res += myTree.query(dfn[y], dfn[x]);
	return res - myTree.query(dfn[lca], dfn[lca]);
}

int val[MAXN];

inline int getNode(int node){
	int x = edge[node << 1].to, y = edge[(node - 1) << 1 | 1].to;
	return dep[x] > dep[y] ? x : y;
}

inline int min(const int& a, const int& b){
	return a < b ? a : b;
}

int d[MAXN];

int getf(int node){
	return d[node] == node ? node : d[node] = getf(d[node]);
}

const int root = 1;
int ex;

int main(){
	std::scanf("%d%d", &n, &q);
	for(int i = 1; i <= n; ++i)
		d[i] = i;
	for(int u, v, w, i = 1; i <= n; ++i){
		std::scanf("%d%d%d", &u, &v, &w);
		if(getf(u) == getf(v))
			cnt += 2, ex = i, s1 = u, s2 = v, sd = w;
		else{
			add(u, v, w);
			add(v, u, w);
			d[getf(u)] = d[v];
		}
	}
	myTree.set(n);
	dfs1(root, 0);
	dfs2(root, 0, root);
	for(int i = 1; i <= n; ++i)
		myTree.update(dfn[i], weight[i]), val[dfn[i]] = weight[i];
	for(int opt, x, y, i = 1; i <= q; ++i){
		std::scanf("%d%d%d", &opt, &x, &y);
		if(opt == 1){
			if(x == ex)
				sd = y;
			else{
				int tag = dfn[getNode(x)];
				myTree.update(tag, -val[tag]);
				myTree.update(tag, y);
				val[tag] = y;
			}
		}
		else if(opt == 2){
			int res = 0x7fffffff;
			res = min(res, queryPath(x, y));
			res = min(res, queryPath(x, s1) + sd + queryPath(s2, y));
			res = min(res, queryPath(x, s2) + sd + queryPath(s1, y));
			std::printf("%d\n", res);
		}
	}
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/natsuka/p/12627553.html