1023 - 42个最短路? -The Shortest Statement (codeforces 1051F)

xiaoxiao2022-06-11  45

传送门

分析

好题,值得做一下 注意到m-n<=20这个条件 将原来的m条边看做(n-1)条树边,(m-n+1)条非树边 对于树边直接lca求距离。 由于非树边最多21条。 因此我们对这21条边连接的42个点都跑一次最短路来更新答案的最小值即可。 注意离散化,虽然点只有42个,但点的编号可能很大 注意数据范围,long long 类型的INF要开大一些,一般的调试方法,将题目中给出的小样例,调大其权值

代码

#include<bits/stdc++.h> #define in read() #define N 100009 #define ll long long #define inf (1ll<<50) using namespace std; inline int read(){ int ans=0; char ch=getchar(); while(!isdigit(ch))ch=getchar(); while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar(); return ans; } int n,m; int nxt[N<<1],head[N],cnt=1; int fa[N][25],dep[N]; ll d[50][N],dtree[N]; int key[N<<1],num=0; bool is_tree[N<<1],vis[N]; struct egde{ int u,v; ll w; }E[N<<1]; void add(int x,int y,int z){ nxt[++cnt]=head[x];head[x]=cnt;E[cnt].v=y;E[cnt].w=z;E[cnt].u=x; nxt[++cnt]=head[y];head[y]=cnt;E[cnt].v=x;E[cnt].w=z;E[cnt].u=y; } void dfs1(int u,int fu){ fa[u][0]=fu;dep[u]=dep[fu]+1; for(int e=head[u];e;e=nxt[e]){ int v=E[e].v; if(v==fu||fa[v][0]) continue; is_tree[e]=is_tree[e^1]=1; dtree[v]=dtree[u]+E[e].w; dfs1(v,u); } } void spfa(int S){ queue<int > q; int s=key[S]; d[S][s]=0;q.push(s); while(!q.empty()){ int u=q.front();q.pop();vis[u]=0; for(int e=head[u];e;e=nxt[e]){ int v=E[e].v; if(d[S][v]>d[S][u]+E[e].w){ d[S][v]=d[S][u]+E[e].w; if(!vis[v]){ q.push(v); vis[v]=1; } } } } } int getlca(int x,int y){ if(dep[x]<dep[y]) swap(x,y); int i; for(i=20;i>=0;--i) if(dep[fa[x][i]]>=dep[y]) x=fa[x][i]; if(x==y) return x; for(i=20;i>=0;--i) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; return fa[x][0]; } int main(){ n=in;m=in; int i,j,k,u,v,w; for(int i=1;i<=44;++i) for(int j=1;j<=n;++j) d[i][j]=inf; for(i=1;i<=m;++i){ u=in;v=in;w=in; add(u,v,w); } dfs1(1,n+1); for(i=2;i<=cnt;i+=2) if(!is_tree[i]) key[++num]=E[i].u,key[++num]=E[i].v; sort(key+1,key+num+1); int numm=unique(key+1,key+num+1)-key-1; for(i=1;i<=numm;++i){ spfa(i); } for(j=1;j<=20;++j) for(i=1;i<=n;++i) fa[i][j]=fa[fa[i][j-1]][j-1]; int q; q=in; for(i=1;i<=q;++i){ u=in;v=in; int lca=getlca(u,v); ll ans=dtree[u]+dtree[v]-2*dtree[lca]; for(j=1;j<=numm;++j){ ans=min(ans,d[j][u]+d[j][v]); } cout<<ans<<'\n'; } return 0; }
转载请注明原文地址: https://www.6miu.com/read-4931661.html

最新回复(0)