CF1051F The Shortest Statement
题解
首先明确,肯定不能跑
那该怎么做?数据范围其实有提示,当
考虑环套树的情况,相当于在一棵确定好的树上加上一些非树边。先预处理求出这棵树的倍增数组和每个节点到根节点的距离。
此时非树边对于答案有影响,当且仅当新的最短路径经过这条非树边,也经过这条非树边的端点。所以找出所有非树边的端点,以每个端点为起点跑 dijkstra ,预处理求出最多
对于每个询问
一个细节
关于
然而由于不是特别好实现(偷懒),本人代码中还是把每条非树边的两个端点都记录了,因此数组也开了两倍(
代码
代码看着很长,其实全是板子。
#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f,N = 1e5+10;
#define ll long long
#define pr pair<ll,int>
#define MP make_pair
inline ll read()
{
ll ret=0;char ch=' ',c=getchar();
while(!(c>='0'&&c<='9')) ch=c,c=getchar();
while(c>='0'&&c<='9') ret=(ret<<1)+(ret<<3)+c-'0',c=getchar();
return ch=='-'?-ret:ret;
}
int n,m,Q;
int ecnt=-1,head[N];
ll dis[100][N],cnt,pot[100];
int f[20][N],dep[N];
bool vis[N],pass[N],used[N];
struct edge
{
int nxt,to,w;
}a[(N<<1)+100];
inline void add(int x,int y,int w)
{
a[++ecnt]=(edge){head[x],y,w};
head[x]=ecnt;
}
inline void dijk(int st,const int id)
{
priority_queue<pr,vector<pr>,greater<pr> >q;
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++) dis[id][i]=1e18;
dis[id][st]=0ll;
q.push(MP(0,st));
while(!q.empty())
{
int u=q.top().second; q.pop();
if(vis[u]) continue;
vis[u]=1;
for(int i=head[u];~i;i=a[i].nxt)
{
int v=a[i].to;
if(dis[id][v]>dis[id][u]+a[i].w)
{
dis[id][v]=dis[id][u]+a[i].w;
q.push(MP(dis[id][v],v));
}
}
}
return;
}
void dfs(int u,int fa)
{
pass[u]=1;
for(int i=1;i<=19;i++) f[i][u]=f[i-1][f[i-1][u]];
for(int i=head[u];~i;i=a[i].nxt)
{
int v=a[i].to;
if(v==fa) continue;
if(pass[v])
{
if(!used[v]) pot[++cnt]=v,used[v]=1;
continue;
}
dis[0][v]=dis[0][u]+a[i].w;
dep[v]=dep[u]+1;
f[0][v]=u;
dfs(v,u);
}
}
inline int lca(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
for(int i=19;i>=0;i--)
if(dep[f[i][x]]>=dep[y]&&f[i][x]) x=f[i][x];
if(x==y) return x;
for(int i=19;i>=0;i--)
if(f[i][x]!=f[i][y]) x=f[i][x],y=f[i][y];
return f[0][x];
}
inline ll Dis(int x,int y){return dis[0][x]+dis[0][y]-(dis[0][lca(x,y)]<<1);}
int main()
{
//freopen("path.in","r",stdin);
//freopen("path.out","w",stdout);
memset(head,-1,sizeof(head));
n=read(),m=read();
for(int i=1;i<=m;i++)
{
int u=read(),v=read(),w=read();
add(u,v,w),add(v,u,w);
}
dfs(1,0);
for(int i=1;i<=cnt;i++) dijk(pot[i],i);
Q=read();
while(Q--)
{
int u=read(),v=read();
ll ans=Dis(u,v);
// printf("ans=%lld\n",ans);
for(int i=1;i<=cnt;i++)
ans=min(ans,dis[i][u]+dis[i][v]);
printf("%lld\n",ans);
}
return 0;
}