[CF1051F]The Shortest Statement

题目大意:给定一张$n$个点$m$条有权边的无向联通图,$q$次询问两点间的最短路

$n\le100000$,$m\le100000$,$1\le100000$,$m$-$n\le20$.

首先看到$m$-$n\le20$这条限制,我们可以想到是围绕这个20来做这道题。

即如果我们随便在图上找一棵树,有最多21条非树边,连接最多42个顶点

考虑两点$x,y$之间的最短路就是某个点到$x$和$y$的最短路之和

首先对于只走树边的情况,这个点是两点的$LCA$

如果经过非树边,$x$或$y$到枚举的这个点的最短路上的最后一条边一定是非树边(如果都是树边的话完全可以转化到一个连接着非树边的点上去)

然后对于所有连接非树边的点都跑一遍最短路,询问时直接枚举这些点取$min$即可

代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<queue>
  5 #include<algorithm>
  6 #define M 200010
  7 #define int long long
  8 using namespace std;
  9 int read()
 10 {
 11     char ch=getchar();int x=0;
 12     while(ch>'9'||ch<'0') ch=getchar();
 13     while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=getchar();
 14     return x;
 15 }
 16 struct point{
 17     int to,next,dis;
 18 }e[M<<1];
 19 int n,m,num,Q,top;
 20 int q[M],head[M],deep[M],dist[M];
 21 int dis[50][M],fa[M][25];
 22 bool vis[M];
 23 struct node{int id,dis;};
 24 bool operator < (node a1,node a2) {return a1.dis>a2.dis;}
 25 void add(int from,int to,int dis)
 26 {
 27     e[++num].next=head[from];
 28     e[num].to=to;
 29     e[num].dis=dis;
 30     head[from]=num;
 31 }
 32 void dfs(int x,int f)
 33 {
 34     vis[x]=true; fa[x][0]=f;
 35     for(int i=head[x];i;i=e[i].next)
 36     {
 37         int to=e[i].to;
 38         if(to==f) continue;
 39         if(vis[to]) q[++top]=x,q[++top]=to;
 40         else
 41         {
 42             deep[to]=deep[x]+1;
 43             dist[to]=dist[x]+e[i].dis;
 44             dfs(to,x);
 45         }
 46     }
 47 }
 48 int lca(int x,int y)
 49 {
 50     if(deep[x]<deep[y]) swap(x,y);
 51     for(int i=19;i>=0;i--)
 52         if(deep[fa[x][i]]>=deep[y])
 53             x=fa[x][i];
 54     if(x==y) return x;
 55     for(int i=19;i>=0;i--)
 56         if(fa[x][i]!=fa[y][i])
 57             x=fa[x][i],y=fa[y][i];
 58     return fa[x][0];
 59 }
 60 void Dijkstra(int id)
 61 {
 62     memset(dis[id],63,sizeof(dis[id]));
 63     memset(vis,false,sizeof(vis));
 64     priority_queue<node>Q;
 65     dis[id][q[id]]=0;
 66     Q.push((node){q[id],0});
 67     while(!Q.empty())
 68     {
 69         int x=Q.top().id;Q.pop();
 70         if(vis[x]) continue;
 71         vis[x]=true;
 72         for(int i=head[x];i;i=e[i].next)
 73         {
 74             int to=e[i].to;
 75             if(!vis[to]&&dis[id][x]+e[i].dis<dis[id][to])
 76             {
 77                 dis[id][to]=dis[id][x]+e[i].dis;
 78                 Q.push((node){to,dis[id][to]});
 79             }
 80         }
 81     }
 82 }
 83 #undef int
 84 int main()
 85 {
 86     #define int long long
 87     n=read(); m=read();
 88     for(int i=1;i<=m;i++) 
 89     {
 90         int a=read(),b=read(),c=read();
 91         add(a,b,c); add(b,a,c);
 92     }
 93     deep[1]=1;dfs(1,0);
 94     for(int j=1;j<=19;j++)
 95         for(int i=1;i<=n;i++)
 96             fa[i][j]=fa[fa[i][j-1]][j-1];
 97     sort(q+1,q+1+top); top=unique(q+1,q+1+top)-q-1;
 98     for(int i=1;i<=top;i++) Dijkstra(i);
 99     Q=read();
100     while(Q--)
101     {
102         int x=read(),y=read();
103         int ans=dist[x]+dist[y]-2*dist[lca(x,y)];
104         for(int i=1;i<=top;i++) ans=min(ans,dis[i][x]+dis[i][y]);
105         printf("%lld\n",ans);
106     }
107     return 0;
108 }

 

转载于:https://www.cnblogs.com/Slrslr/p/9688196.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值