题解:建立圆方树,每个点向环内深度最浅的点连边
分LCA是不是方点讨论即可
如果是方点讨论从哪边绕过去的
园点的话直接用最短路处理即可
问题:双联通分量不熟
#include<iostream> #include<cstdio> #include<cstring> #include<vector> #include<queue> #include<stack> #include<map> using namespace std; const int maxn=100009; const int inf=1000000000; int n,m,T; map<int,int>ma[maxn]; struct Edge{ int from,to,dist; }; vector<int>G[maxn]; vector<Edge>edges; void Addedge(int x,int y,int z){ Edge e; e.from=x;e.to=y;e.dist=z; edges.push_back(e); G[x].push_back(edges.size()-1); } queue<int>q; int inq[maxn]; int d[maxn]; void Spfa(){ for(int i=1;i<=n;++i){ d[i]=inf;inq[i]=0; } d[1]=0;inq[1]=1;q.push(1); while(!q.empty()){ int x=q.front();q.pop();inq[x]=0; for(int i=0;i<G[x].size();++i){ Edge e=edges[G[x][i]]; if(d[x]+e.dist<d[e.to]){ d[e.to]=d[x]+e.dist; if(!inq[e.to]){ q.push(e.to); inq[e.to]=1; } } } } } int dfsclock,scccnt; int pre[maxn],lowlink[maxn],ref[maxn]; int lastpoint[maxn],restedge[maxn]; int S[maxn],top; int dt[maxn]; int vis[maxn]; int depth[maxn]; int father[maxn]; vector<int>son[maxn]; void Dfs(int u,int fa){ // printf("now in point %d\n",u); // for(int i=1;i<=5e8;++i); pre[u]=lowlink[u]=++dfsclock; ref[dfsclock]=u; S[++top]=u; // cout<<u<<‘ ‘<<S.size()<<endl; for(int i=0;i<G[u].size();++i){ Edge e=edges[G[u][i]]; // if(edges[G[u][i]^1].from==fa)continue; int v=e.to; if(v==fa)continue; if(!pre[v]){ dt[v]=dt[u]+e.dist; Dfs(v,u); lowlink[u]=min(lowlink[u],lowlink[v]); }else if(!vis[v]){ // cout<<u<<‘ ‘<<v<<endl; lowlink[u]=min(lowlink[u],pre[v]); restedge[u]=e.dist; for(int i=top;S[i]!=v;--i){ int x=S[i]; // cout<<x<<‘ ‘<<v<<endl; if(x==v)break; father[x]=v; lastpoint[x]=u; son[v].push_back(x); // printf("push(%d)\n",x); // if(S.size()==0)cout<<u<<endl; } } } // cout<<u<<" AFSD "<<S.size()<<endl; if(lowlink[u]==pre[u]){ father[u]=fa; son[fa].push_back(u); // printf("push(%d)\n",u); } --top; vis[u]=1; // printf("now out point %d\n",u); } void Getdepth(int now,int fa){ depth[now]=depth[fa]+1; for(int i=0;i<son[now].size();++i){ if(son[now][i]==fa)continue; Getdepth(son[now][i],now); } } int f[maxn][20]; void LCAinit(){ for(int i=1;i<=n;++i)f[i][0]=father[i]; for(int j=1;j<=19;++j){ for(int i=1;i<=n;++i){ f[i][j]=f[f[i][j-1]][j-1]; } } } int Getlca(int x,int y){ if(depth[x]<depth[y])swap(x,y); for(int j=19;j>=0;--j){ if(depth[f[x][j]]>=depth[y])x=f[x][j]; } if(x==y)return x; for(int j=19;j>=0;--j){ if(f[x][j]!=f[y][j]){ x=f[x][j];y=f[y][j]; } } return f[x][0]; } int Getpoint(int x,int y){ for(int j=19;j>=0;--j){ if(depth[f[x][j]]>depth[y])x=f[x][j]; } return x; } int Getans(int x,int y){ if(depth[x]<depth[y])swap(x,y); int lca=Getlca(x,y); // cout<<"lca="<<lca<<endl; if(lca==y){ // if(d[x]-d[y]==6760174)cout<<"AD"<<endl; return d[x]-d[y]; } int px=Getpoint(x,lca); int py=Getpoint(y,lca); if((lastpoint[px]!=lastpoint[py])||(lastpoint[px]==0)||(lastpoint[py]==0)){ return d[x]+d[y]-2*d[lca]; }else{ int ans=d[x]+d[y]-d[px]-d[py]; int tmp; if(dt[px]>dt[py])tmp=dt[px]-dt[py]; else tmp=dt[py]-dt[px]; // printf("%d %d\n",lastpoint[px],restedge[lastpoint[px]]); int ans1=ans+tmp; int ans2=ans+restedge[lastpoint[px]]+dt[lastpoint[px]]-dt[ref[lowlink[px]]]-tmp;//6760174 if(ans2==6760174){ printf("tmp=%d lastpoint=%d ref[]=%d\n",tmp,lastpoint[py],ref[lowlink[px]]); } return min(ans1,ans2); } } int main(){ // freopen("cactus.in","r",stdin); // freopen("cactus.out","w",stdout); // scanf("%d%d%d",&n,&m,&T); while(m--){ int x,y,z; scanf("%d%d%d",&x,&y,&z); if(ma[x].count(y)){ ma[x][y]=min(ma[x][y],z); }else if(ma[y].count(x)){ ma[y][x]=min(ma[y][x],z); }else{ ma[x][y]=z; } } for(int i=1;i<=n;++i){ for(map<int,int>::iterator it=ma[i].begin();it!=ma[i].end();++it){ Addedge(i,it->first,it->second); Addedge(it->first,i,it->second); } } Spfa(); Dfs(1,0); Getdepth(1,0); LCAinit(); // for(int i=1;i<=n;++i)cout<<depth[i]<<‘ ‘; // cout<<endl; while(T--){ int x,y; scanf("%d%d",&x,&y); printf("%d\n",Getans(x,y)); } return 0; }