CF1051F The Shortest Statement
CF1051F The Shortest Statement
题目描述
You are given a weighed undirected connected graph, consisting of n n vertices and m m edges.
You should answer q q queries, the \(i\) -th query is to find the shortest distance between vertices \(u_i\) and \(v_i\).
输入输出格式
输入格式:
The first line contains two integers \(n\) and \(m\) \((1 \le n, m \le 10^5, m - n \le 20)\) — the number of vertices and edges in the graph.
Next \(m\) lines contain the edges: the \(i\) -th edge is a triple of integers \(v_i, u_i, d_i\) \((1 \le u_i, v_i \le n, 1 \le d_i \le 10^9, u_i \neq v_i)\).
This triple means that there is an edge between vertices \(u_i\) and \(v_i\) of weight \(d_i\) . It is guaranteed that graph contains no self-loops and multiple edges.
The next line contains a single integer \(q~(1 \le q \le 10^5)\) — the number of queries.
Each of the next \(q\) lines contains two integers \(u_i\) and \(v_i~(1 \le u_i, v_i \le n)\) — descriptions of the queries.
Pay attention to the restriction \(m - n ~ \le ~ 20\).
输出格式:
Print \(q\) lines.
The \(i\) -th line should contain the answer to the \(i\) -th query — the shortest distance between vertices \(u_i\) and \(v_i\).
不错的题目
发现Pay \ attention...,所以肯定有用了(一般看数据范围这么奇怪也会想到吧
思路:先跑一颗生成树,然后把不在生成树的边的端点拿出来,以每个端点跑最短路。询问直接枚举经过哪个端点或者直接是树上路径
Code:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define ll long long
const int N=1e5+10;
int n,m,Q;
int head[N],to[N<<1],Next[N<<1],cnt=1;
ll edge[N<<1],dis[N];
void add(int u,int v,ll w)
{
to[++cnt]=v,Next[cnt]=head[u],edge[cnt]=w,head[u]=cnt;
}
int is[N<<1],used[N],f[N][21],dep[N];
void dfs(int now)
{
for(int i=1;f[now][i-1];i++) f[now][i]=f[f[now][i-1]][i-1];
used[now]=1;
for(int i=head[now];i;i=Next[i])
{
int v=to[i];
if(!used[v])
{
is[i]=is[i^1]=1;
dis[v]=dis[now]+edge[i];
f[v][0]=now;
dep[v]=dep[now]+1;
dfs(v);
}
}
}
int LCA(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
for(int i=20;~i;i--)
if(dep[f[x][i]]>=dep[y])
x=f[x][i];
if(x==y) return x;
for(int i=20;~i;i--)
if(f[x][i]!=f[y][i])
x=f[x][i],y=f[y][i];
return f[x][0];
}
int point[100],tot;
#define P pair <ll,int>
priority_queue <P,vector <P>,greater <P> > q;
ll diss[100][N];
void dijs()
{
memset(diss,0x3f,sizeof(diss));
for(int i=1;i<=tot;i++)
{
int u=point[i];
diss[i][u]=0;
q.push(make_pair(0,u));
memset(used,0,sizeof(used));
while(!q.empty())
{
int now=q.top().second;
q.pop();
if(used[now]) continue;
used[now]=1;
for(int j=head[now];j;j=Next[j])
{
int v=to[j];
if(diss[i][v]>diss[i][now]+edge[j])
{
diss[i][v]=diss[i][now]+edge[j];
q.push(make_pair(diss[i][v],v));
}
}
}
}
}
int main()
{
scanf("%d%d",&n,&m);
ll w;
for(int u,v,i=1;i<=m;i++)
{
scanf("%d%d%lld",&u,&v,&w);
add(u,v,w),add(v,u,w);
}
dfs(1);
for(int u=1;u<=n;u++)
for(int i=head[u];i;i=Next[i])
{
int v=to[i];
if(!is[i]) point[++tot]=u,point[++tot]=v;
}
sort(point+1,point+1+tot);
tot=unique(point+1,point+1+tot)-point-1;
dijs();
scanf("%d",&Q);
for(int u,v,i=1;i<=Q;i++)
{
scanf("%d%d",&u,&v);
int lca=LCA(u,v);
ll ans=dis[u]+dis[v]-dis[lca]*2;
for(int j=1;j<=tot;j++)
ans=min(ans,diss[j][u]+diss[j][v]);
printf("%lld\n",ans);
}
return 0;
}
2018.10.10