[CF1051F] The Shortest Statement 最短路 lca

传送门

题意

  • 给定一个 n n n条边 m m m个点的带权无向联通图, q q q次询问,每次询问从 u i u_i ui
    v i v_i vi的最短路
    n &lt; = 100000 n&lt;=100000 n<=100000
    m − n &lt; = 20 m-n&lt;=20 mn<=20
    T L = 4 s TL=4s TL=4s

先随便求出1个生成树
那么会有一些边不在生成树上,将这些边的端点标记为关键点
由于 n − m n-m nm很小,则关键点的数量很少,我们可以对每个关键点求最短路
然后对于每次查询,我们可以查询 u i u_i ui v i v_i vi在树上的距离,然后枚举每个关键点到 u i u_i ui v i v_i vi的距离
由于树上距离要求lca,则时间复杂度为 O ( ( m − n ) n l o g n + q n ( l o g n + ( m − n ) ) ) O((m-n)nlogn+qn(logn+(m-n))) O((mn)nlogn+qn(logn+(mn)))

code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+100,inf=0x3f3f3f3f;
const ll INF=1e18;
inline int read(){
	int x=0,f=1;char ch=getchar();
	for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
	for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+(ch^48);
	return x*f;
}
int st[maxn],fi[maxn],val[maxn],fa[maxn],n,m;
inline int find(int x){
	return x==fa[x]?x:fa[x]=find(fa[x]);
}
inline void Merge(int x,int y){
	x=find(x),y=find(y);
	if(x^y)fa[x]=y;
}
inline bool judge(int x,int y){
	x=find(x),y=find(y);
	return x==y;
}
int fst[maxn],lst[maxn<<1],to[maxn<<1],w[maxn<<1],e;
inline void add(int x,int y,int z){
	to[++e]=y,lst[e]=fst[x],fst[x]=e,w[e]=z;
}
int Fst[maxn],Lst[maxn<<1],To[maxn<<1],W[maxn<<1],E;
inline void Add(int x,int y,int z){
	To[++E]=y,Lst[E]=Fst[x],Fst[x]=E,W[E]=z;
}
struct node{
	ll d;int u;
	bool operator<(const node &rhs)const{
		return d>rhs.d;		
	}
};
int id[maxn],vl[maxn],f[maxn][25],d[maxn],cnt;
ll dis[50][maxn],dep[maxn];
inline void dijkstra(int s){
	for(register int i=1;i<=n;++i)dis[s][i]=INF;
	dis[s][vl[s]]=0;
	priority_queue<node>q;q.push((node){0,vl[s]});
	while(!q.empty()){
		int u=q.top().u;ll d=q.top().d;q.pop();
		if(d^dis[s][u])continue;
		for(register int i=Fst[u];i;i=Lst[i]){
			int v=To[i];
			if(dis[s][v]>dis[s][u]+W[i]){
				dis[s][v]=dis[s][u]+W[i];
				q.push((node){dis[s][v],v});
			}
		}
	}
}
inline void dfs(int x,int ff){
	f[x][0]=ff;
	for(register int i=1;i<=20;++i)f[x][i]=f[f[x][i-1]][i-1];
	for(register int i=fst[x];i;i=lst[i]){
		int v=to[i];
		if(v^ff)dep[v]=dep[x]+w[i],d[v]=d[x]+1,dfs(v,x);
	}
}
inline int lca(int x,int y){
	if(d[x]<d[y])swap(x,y);
	for(register int i=0,z=d[x]-d[y];z;++i,z>>=1)if(z&1)x=f[x][i];
	if(x==y)return x;
	for(register int i=20;~i;--i)if(f[x][i]^f[y][i])x=f[x][i],y=f[y][i];
	return f[x][0];
}
inline void init(){
	for(register int i=1;i<=n;++i)fa[i]=i;
	for(register int i=1;i<=m;++i){
		Add(st[i],fi[i],val[i]),A	int cl=clock();dd(fi[i],st[i],val[i]);
		if(judge(st[i],fi[i])){	int cl=clock();
			if(!id[st[i]])id[st[i]]=++cnt,vl[cnt]=st[i];
			if(!id[fi[i]])id[fi[i]]=++cnt,vl[cnt]=fi[i];
			continue;
		}add(st[i],fi[i],val[i]),add(fi[i],st[i],val[i]);
		Merge(st[i],fi[i]);	int cl=clock();
	}cerr<<cnt<<endl;
	for(register int i=1;i<=cnt;++i)dijkstra(i);
	dfs(1,0);
}
inline void solve(){
	int q=read();
	while(q--){
		int x=read(),y=read();
		ll res=INF;
		for(register int i=1;i<=cnt;++i)res=min(res,dis[i][x]+dis[i][y]);
		res=min(res,dep[x]+dep[y]-2*dep[lca(x,y)]);
		printf("%lld\n",res);
	}
}
int main(){
	freopen("CF1051F.in","r",stdin);
	freopen("CF1051F.out","w",stdout);
	n=read(),m=read();
	for(register int i=1;i<=m;++i)st[i]=read(),fi[i]=read(),val[i]=read();
	init(),solve();
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值