标签:efi stat mem while getchar use short 之间 eof
题目大意:一个无向连通图,n个点m条边,n<=1e5,m-n<=20,q个询问,q<=1e5,求u和v之间的最短路
发现边只比点多20个,所以可以把图当成一棵树,求出图的最小生成树
对于一个询问,最短路径可能是两个点的树上最小距离,但最短路径也有可能经过未被加入最小生成树的边
那怎么办呢?
发现m-n<=20,预处理出未被加入最小生成树的边,相连的其中一个节点,去跑spfa(因为是稀疏图不怕被卡),一共跑21次spfa即可
如果最短路径经过未被加入最小生成树的边,那么一定经过这条边相连的两个节点
每个询问的答案就是最小生成树上两点的距离 或者是 这21次spfa中两点之间的距离即可
时间$O(20(n+e+q))$,稀疏图spfa时间近似等于$(O(n+e))$
1 #include <queue> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #define ll long long 6 #define N 100010 7 #define uint unsigned int 8 #define inf 0x3f3f3f3f3f3f3fll 9 using namespace std; 10 //re 11 int gint() 12 { 13 int ret=0,fh=1;char c=getchar(); 14 while(c<‘0‘||c>‘9‘){if(c==‘-‘)fh=-1;c=getchar();} 15 while(c>=‘0‘&&c<=‘9‘){ret=(ret<<3)+(ret<<1)+c-‘0‘;c=getchar();} 16 return ret*fh; 17 } 18 19 int n,m,cte,num; 20 int head[N],fa[N]; 21 struct Edge{int to,nxt;ll val;}edge[N*2]; 22 23 int find_fa(int x){ 24 int y=x,pre;while(y!=fa[y])y=fa[y]; 25 while(fa[x]!=y){pre=fa[x],fa[x]=y,x=pre;} 26 return y; 27 } 28 void ae(int u,int v,int w){ 29 cte++;edge[cte].to=v,edge[cte].val=w; 30 edge[cte].nxt=head[u],head[u]=cte; 31 } 32 33 struct Krus{int x,y,flag;ll val;}e[N]; 34 int cmp(Krus s1,Krus s2){return s1.val<s2.val;} 35 void Kruskal() 36 { 37 int x,y,fx,fy; 38 for(int i=1;i<=n;i++) fa[i]=i; 39 sort(e+1,e+m+1,cmp); 40 for(int i=1;i<=m;i++){ 41 x=e[i].x,y=e[i].y,fx=find_fa(x),fy=find_fa(y); 42 if(fx!=fy) e[i].flag=1,fa[fy]=fx,ae(x,y,e[i].val),ae(y,x,e[i].val); 43 }memset(fa,0,sizeof(fa)); 44 } 45 46 int use[N]; 47 struct SBFA{ 48 ll dis[N];int S; 49 void Main(int s) 50 { 51 memset(dis,0x3f,sizeof(dis)); 52 S=s;queue<int>q;q.push(S); 53 dis[S]=0,use[S]=1; 54 while(!q.empty()){ 55 int u=q.front();q.pop(); 56 for(int j=head[u];j;j=edge[j].nxt){ 57 int v=edge[j].to; 58 if(dis[v]>dis[u]+edge[j].val){ 59 dis[v]=dis[u]+edge[j].val; 60 if(!use[v]) q.push(v),use[v]=1; 61 } 62 }use[u]=0; 63 } 64 } 65 }sbfa[22]; 66 67 ll dis[N];int dep[N],sz[N],son[N],tp[N]; 68 void dfs1(int u,int dad) 69 { 70 for(int j=head[u];j;j=edge[j].nxt){ 71 int v=edge[j].to; 72 if(v==dad) continue; 73 fa[v]=u,dep[v]=dep[u]+1; 74 dis[v]=dis[u]+edge[j].val; 75 dfs1(v,u);sz[u]+=sz[v]; 76 son[u]=sz[v]>sz[son[u]]?v:son[u]; 77 }sz[u]++; 78 } 79 void dfs2(int u){ 80 if(son[u]) tp[son[u]]=tp[u],dfs2(son[u]); 81 for(int j=head[u];j;j=edge[j].nxt){ 82 int v=edge[j].to; 83 if(v==fa[u]||v==son[u]) continue; 84 tp[v]=v;dfs2(v); 85 } 86 } 87 int Lca(int x,int y){ 88 while(tp[x]!=tp[y]){ 89 if(dep[tp[x]]<dep[tp[y]]) swap(x,y); 90 x=fa[tp[x]]; 91 }return dep[x]<dep[y]?x:y; 92 } 93 94 ll solve(int x,int y){ 95 int lca=Lca(x,y); 96 ll ans=dis[x]+dis[y]-dis[lca]*2; 97 for(int i=0;i<num;i++) 98 ans=min(ans,sbfa[i].dis[x]+sbfa[i].dis[y]); 99 return ans; 100 } 101 102 int main() 103 { 104 scanf("%d%d",&n,&m); 105 int x,y; 106 for(int i=1;i<=m;i++) 107 e[i].x=gint(),e[i].y=gint(),e[i].val=gint(); 108 Kruskal(); 109 dep[1]=1,dfs1(1,-1); 110 tp[1]=1,dfs2(1); 111 for(int i=1;i<=m;i++) 112 if(!e[i].flag){ae(e[i].x,e[i].y,e[i].val),ae(e[i].y,e[i].x,e[i].val);} 113 for(int i=1;i<=m;i++) 114 if(!e[i].flag){sbfa[num].Main(e[i].x),num++;} 115 int q;scanf("%d",&q); 116 for(int i=1;i<=q;i++){ 117 x=gint(),y=gint(); 118 printf("%I64d\n",solve(x,y)); 119 } 120 return 0; 121 }
CF 1051F The Shortest Statement (最短路)
标签:efi stat mem while getchar use short 之间 eof
原文地址:https://www.cnblogs.com/guapisolo/p/9811763.html