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 eq 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
",ans);
}
return 0;
}
2018.10.10