D. Shortest Path Query(二叉树 + 最短路)

https://codeforces.ml/group/DOZ49JViPG/contest/376619/problem/D(题目链接)

There is an undirected graph with n vertices and m edges. The vertices are labelled by 1,2,…,n. The i-th edge connects the ui-th vertex and the vi-th vertex, the length of which is wi. Here, ui's binary representation is always a prefix of vi's binary representation. Both binary representations are considered without leading zeros. For example, ui=210=102, vi=510=1012.

You will be given q queries. In the i-th query, you will be given two integers si and ti. Please write a program to figure out the length of the shortest path from the si-th vertex to the ti-th vertex, or determine there is no path between them.

类似于一棵二叉树的的结构,因为题目所给边的两个端点一定满足一个端点是另一个端点的前缀,所以两个点之间若存在路相连,则一定经过这两个点的公共祖先,所以只要迪杰斯特拉暴力求解所有可作为祖先到其子树的最短路,再求询问的两个点的公共祖先, ans = min(ans, dis[lca][u] + dis[lca][v])

#include<iostream>
#include<algorithm>
#include<string> 
#include<set> 
#include<map>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#include<stack>
#include<unordered_map>
#include<iomanip>
#define ll long long
#define ull unsigned long long
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr)
#define m_p make_pair
#define pi acos(-1)
using namespace std;

const int N = 1e5 + 5;
const double eps = 1e-4;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
//const ll mod = 1000003;
inline ll qpow(ll x, ll y, ll M){ll ans=1;while(y){if(y&1)ans=ans*x%M;x=x*x%M;y=y>>1;}return ans;}
inline ll gcd(ll x, ll y){return y?gcd(y,x%y):x;}

ll n, m, q;
ll bit[N];
vector<pair<ll, ll>> e[N];
ll vis[N][20];
ll dis[N][20];//dis[i][j] : i的祖先与i的深度差为j时的最短路

void dijkstra(ll st)//最短路求st到其子节点的最短路
{
	priority_queue<pair<ll, ll>, vector<pair<ll, ll>>, greater<pair<ll, ll>>> q;
	q.push({0, st});
	dis[st][0] = 0;
	while(q.size())
	{
		pair<ll, ll> now = q.top();
		q.pop();
		ll dep = 0;
		for(ll i = now.second; i != st; i /= 2)//深度
			dep++;
		if(vis[now.second][dep])
			continue;
		vis[now.second][dep] = 1;
		for(ll i = 0; i < e[now.second].size(); i++)
		{
			ll to = e[now.second][i].first, w = e[now.second][i].second;
			ll dep_to = 0;
			if(to < st)
				continue;
			for(ll j = to; j != st; j /= 2)
				dep_to++;
			if(dis[to][dep_to] > dis[now.second][dep] + w)
			{
				dis[to][dep_to] = dis[now.second][dep] + w;
				q.push({dis[to][dep_to], to});
			} 
		}
	}
}

void solve()
{
	memset(dis, INF, sizeof dis);
	cin>>n>>m;
	for(ll i = 1, u, v, w; i <= m; i++)
	{
		cin>>u>>v>>w;
		e[u].push_back({v, w});
		e[v].push_back({u, w});
	}	
	
	for(ll i = 1; i <= n; i++)
		dijkstra(i);
		
	for(ll i = 1; i <= n; i++)
		bit[i] = bit[i>>1] + 1;	
	cin>>q;
	while(q--)
	{
		ll x, y;
		cin>>x>>y;
		if(x < y)	
			swap(x, y);
		ll xx = x, yy = y, depx = 0, depy = 0, ans = INF;	
		while(bit[xx] != bit[yy])//将x,y深度变成相同
		{
			xx /= 2;
			depx++;
		}
		while(1)寻找x, y的公共祖先,并记录答案
		{
			if(xx == yy)
				ans = min(ans, dis[x][depx] + dis[y][depy]);
			if(xx == 1)
				break;
			xx /= 2;
			yy /= 2;
			depx++;
			depy++;
		}	
		if(ans == INF)
			cout<<-1<<'\n';
		else
			cout<<ans<<'\n'; 
	}
} 

signed main()
{
	IOS;
	//init();
	ll t = 1;
	//cin>>t;
	while(t--)	
		solve();
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值