ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF1051F The Shortest Statement 题解

2021-11-11 18:05:09  阅读:204  来源: 互联网

标签:treedis read 题解 ll Statement include e1 Shortest dis


题目链接

给定一个树,在树上加k条边,求全源最短路。(\(n \le 10^5 \space, k \le 20\))

显然利用树的性质,考虑如何处理加的20条边即可。可以枚举所有经过的非树边,对每个非树边的端点依次更新答案,再结合树上路径长度即可。

最小生成树+lca+dij即可解决的一道紫题...

写的时候要注意不同的图、树的混淆问题。

把lca板子写错调了一小时??? 有时候对树上深度总有种从下到上的错觉。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstring>
#include <assert.h>
#include <map>
#define ll long long
using namespace std;
const ll N = 100005, M = 200005,INF = 1e14;
ll n, m, Q;
ll cnt1, head1[M], cnt2, head2[M];
ll cnt, vis[N], dep[N], fa[N], f[N][23];
ll dis[45][N], treedis[N], tot,await[N];
struct edge {
	ll from, to, next;
	ll dis;
} e1[M], e2[M];
struct EDGE {
	ll u, v, d;
} e[M];
int read() {
	register int x=0,f=1;
	register char s=getchar();
	while(s>'9'||s<'0') {
		if(s=='-') f=-1;
		s=getchar();
	}
	while(s>='0'&&s<='9') {
		x=x*10+s-'0';
		s=getchar();
	}
	return x*f;
}
void add1(ll u, ll v, ll dis) {
	e1[++cnt1].from = u;
	e1[cnt1].to = v;
	e1[cnt1].next = head1[u];
	e1[cnt1].dis = dis;
	head1[u] = cnt1;
}
void add2(ll u, ll v, ll dis) {
	e2[++cnt2].to = v;
	e2[cnt2].from = u;
	e2[cnt2].next = head2[u];
	e2[cnt2].dis = dis;
	head2[u] = cnt2;
}
int cmp(EDGE a, EDGE b) {
	return a.d < b.d;
}
ll find(ll k) {
	return fa[k] == k ? k : fa[k] = find(fa[k]);
}
void dij(ll k) {
	for (int i=1;i<=n;i++)
	  vis[i]=0,dis[k][i]=INF;
	priority_queue<pair<ll,int> > q;
	dis[k][await[k]] = 0ll;
	q.push(make_pair(0,await[k]));
	while (!q.empty()) {
		ll x = q.top().second;
		q.pop();
		if (vis[x]) continue;
		vis[x] = 1;
		for (ll i = head1[x]; i; i = e1[i].next) {
			ll v = e1[i].to;
			if (dis[k][v] > dis[k][x] + e1[i].dis) {
				dis[k][v] = dis[k][x] + e1[i].dis;
				q.push(make_pair(-dis[k][v],v));
			}
		}
	}
}
void dfs(ll k) {
	for (int i=1; i<=20; i++) f[k][i]=f[f[k][i-1]][i-1];
	for (ll i = head2[k]; i; i = e2[i].next) {
		ll v = e2[i].to;
		if (v == f[k][0]) continue;
		f[v][0]=k;
		treedis[v]=treedis[k]+e2[i].dis;
		dep[v]=dep[k]+1;
		dfs(v);
	}
}
ll lca(ll a, ll b) {
	if (dep[a] < dep[b]) swap(a, b);
	for (ll i = 20; i >= 0; i--)
		if (dep[f[a][i]] >= dep[b])
			a = f[a][i];
	if (a == b) return a;
	for (ll i = 20; i >= 0; i--)
		if (f[a][i] != f[b][i]) a = f[a][i], b = f[b][i];
	return f[a][0];
}
int main() {
	n=read(),m=read();
	for (ll i = 1; i <= n; i++) fa[i] = i;
	for (ll i = 1; i <= m; i++) {
		e[i].u=read(),e[i].v=read(),e[i].d=read();
		add1(e[i].u, e[i].v, e[i].d),add1(e[i].v, e[i].u, e[i].d);
	}
	sort(e + 1, e + 1 + m, cmp);
	for (ll i = 1; i <= m; i++) {
		ll f1 = find(e[i].u), f2 = find(e[i].v);
		if (f1 != f2) {
			add2(e[i].u, e[i].v, e[i].d);
			add2(e[i].v, e[i].u, e[i].d);
			fa[f1] = f2;
		} else {
			await[++cnt]=e[i].u;
			await[++cnt]=e[i].v;
		}
	}
	for (int i=1; i<=cnt; i++)  dij(i);
	cin >> Q;
	dfs(1);
	while (Q--) {
		ll x = read(), y = read();
		ll ans = treedis[x] + treedis[y] - 2 * treedis[lca(x, y)];
		for (ll i = 1; i <= cnt; i++)
			ans=min(ans,dis[i][x] + dis[i][y]);
		cout << ans << endl;
	}
}

标签:treedis,read,题解,ll,Statement,include,e1,Shortest,dis
来源: https://www.cnblogs.com/KinuhataSaiai/p/15540964.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有