CF1051F The Shortest Statement Dijkstra + 性质分析
动态询问连通图任意两点间最短路,单次询问.
显然,肯定有一些巧妙地性质(不然你就发明了新的最短路算法了233)
有一点很奇怪:边数最多只比点数多 $20$ 个,那么就可以将这个图看作是一个生成树,上面连了不到 $20$ 条边.
考虑两个点之间地最短路只有两种情况:经过所有只在生成树上的点,或者经过一些连着生成树外的点.
第一个情况非常好求,随便搞一个生成树然后求个距离就行.
对于第二种情况,由于连着生成树外的边的点最多只有 $20$ 个,所以可以对这些点都跑一遍最短路,然后依次枚举即可.
每次询问的复杂度为 $O(log$ $n+20 )$
#include<bits/stdc++.h> using namespace std; void setIO(string s) { string in=s+".in"; freopen(in.c_str(),"r",stdin); } typedef long long ll; const int maxn=100005; const ll inf=10000000000000; struct Union { int p[maxn]; void init() { for(int i=0;i<maxn;++i) p[i]=i; } int find(int x) { return p[x]==x?x:p[x]=find(p[x]); } int merge(int x,int y) { int a=find(x),b=find(y); if(a==b) return 0; p[a]=b; return 1; } }ufs; struct Edge { int u,v,c; }ed[maxn]; namespace tree { int edges; int val[maxn<<1],hd[maxn],to[maxn<<1],nex[maxn<<1]; int dep[maxn],fa[maxn],top[maxn],siz[maxn],son[maxn]; ll dis[maxn]; void addedge(int u,int v,int c) { nex[++edges]=hd[u],hd[u]=edges,to[edges]=v,val[edges]=c; } void dfs1(int u,int ff) { fa[u]=ff,dep[u]=dep[ff]+1,siz[u]=1; for(int i=hd[u];i;i=nex[i]) { int v=to[i]; if(v==ff) continue; dis[v]=dis[u]+1ll*val[i]; dfs1(v,u), siz[u]+=siz[v]; if(siz[v]>siz[son[u]]) son[u]=v; } } void dfs2(int u,int tp) { top[u]=tp; if(son[u]) dfs2(son[u],tp); for(int i=hd[u];i;i=nex[i]) { int v=to[i]; if(v==fa[u]||v==son[u]) continue; dfs2(v,v); } } int LCA(int x,int y) { while(top[x]^top[y]) { dep[top[x]] > dep[top[y]] ? x = fa[top[x]] : y = fa[top[y]]; } return dep[x] < dep[y] ? x : y; } ll Dis(int x,int y) { return dis[x]+dis[y]-(dis[LCA(x,y)]*2); } }; namespace Dijkstra { struct Node { ll dis; int u; Node(ll dis=0,int u=0):dis(dis),u(u){} bool operator<(Node b) const { return dis>b.dis; } }; priority_queue<Node>Q; int edges; int done[maxn], hd[maxn],to[maxn<<1],nex[maxn<<1],val[maxn<<1]; ll d[maxn]; ll dis[50][maxn]; void addedge(int u,int v,int c) { nex[++edges]=hd[u],hd[u]=edges,to[edges]=v,val[edges]=c; } void dijkstra(int s,int idd) { for(int i=0;i<maxn;++i) d[i]=inf,done[i]=0; d[s]=0, dis[idd][s]=0, Q.push(Node(0,s)); while(!Q.empty()) { Node e=Q.top(); Q.pop(); int u=e.u; if(done[u]) continue; done[u]=1, dis[idd][u]=d[u]; for(int i=hd[u];i;i=nex[i]) { int v=to[i]; if(d[u]+val[i]<d[v]) { d[v]=d[u]+1ll*val[i]; Q.push(Node(d[v], v)); } } } } }; int n,m; int mk[maxn],ne[maxn]; int main() { // setIO("input"); scanf("%d%d",&n,&m); ufs.init(); for(int i=1;i<=m;++i) { scanf("%d%d%d",&ed[i].u,&ed[i].v,&ed[i].c); if(ufs.merge(ed[i].u, ed[i].v)) { tree::addedge(ed[i].u, ed[i].v, ed[i].c); tree::addedge(ed[i].v, ed[i].u, ed[i].c); mk[i]=1; } } int cnt=0; tree::dfs1(1,0); tree::dfs2(1,1); for(int i=1;i<=m;++i) if(mk[i]==0) ne[ed[i].u]=ne[ed[i].v]=1; for(int i=1;i<=m;++i) Dijkstra::addedge(ed[i].u, ed[i].v, ed[i].c), Dijkstra::addedge(ed[i].v,ed[i].u,ed[i].c); for(int i=1;i<=n;++i) if(ne[i]) ++cnt, Dijkstra::dijkstra(i,cnt); int Q; scanf("%d",&Q); for(int cas=1;cas<=Q;++cas) { int u,v; scanf("%d%d",&u,&v); ll ans=tree::Dis(u,v); for(int i=1;i<=cnt;++i) ans=min(ans,Dijkstra::dis[i][u]+Dijkstra::dis[i][v]); printf("%I64d\n",ans); } return 0; }