[关闭]
@ysner 2018-06-19T14:42:56.000000Z 字数 3263 阅读 1780

园公逛

图论 强联通分量


题面

给定一个有个顶点条边的带权无向图。现有次询问,每次询问之间的一条环路径(无重边),要求边权最大值最小,输出这个最大值。

解析

算法

暴搜。记得过程要连起来,后者从前者引出。
而不是

  1. dfs(u,v,lim);
  2. if(!flag) return;
  3. dfs(v,u,lim);

。。。

边双联通分量vs点双联通分量

边双无割边(转一圈走两次的边)。
点双无割点(转一圈走两次的点)。(一个环)
所以这道题应用边双,与点双唯一的不同是没有判定过程。

  1. il int tarjan(re int u,re ll lim,re int lst)
  2. {
  3. dfn[u]=low[u]=++tim;sta[++top]=u;re int v;
  4. for(re int i=h[u];i+1;i=e[i].nxt)
  5. {
  6. v=e[i].to;
  7. if(e[i].w>lim||lst==i) continue;
  8. if(!dfn[v]) tarjan(v,lim,i^1),low[u]=min(low[u],low[v]);
  9. else low[u]=min(low[u],dfn[v]);
  10. }
  11. if(low[u]==dfn[u])
  12. do
  13. {
  14. v=sta[top--];
  15. f[v]=u;
  16. }
  17. while(u^v);
  18. }

算法

最大值、最小值,容易想到二分。
于是二分这个值,每次排除掉边权比更大的边,边强联通分量
什么,你说这是无向图?
时不走上次走的边的反边就可以啦。
复杂度

  1. il int check(re int u,re int tar,re ll lim)
  2. {
  3. top=tim=0;fp(i,1,n) dfn[i]=low[i]=0,f[i]=i;
  4. fp(i,1,n) if(!dfn[i]) tarjan(i,lim,-1);
  5. return find(u)==find(tar);
  6. }
  7. int main()
  8. {
  9. n=gi();m=gi();q=gi();
  10. memset(h,-1,sizeof(h));
  11. fp(i,1,n) num[i]=gi();
  12. fp(i,1,m)
  13. {
  14. re int u=gi(),v=gi();ll w=num[u]-num[v];if(w<0) w=-w;
  15. add(u,v,w);add(v,u,w);if(mx<w) mx=w;if(mn>w) mn=w;
  16. }
  17. while(q--)
  18. {
  19. re int u=gi(),v=gi();
  20. re ll l=mn,r=mx,ans=-1;
  21. while(l<=r)
  22. {
  23. re ll mid=l+r>>1;
  24. if(check(u,v,mid))r=mid-1,ans=mid;
  25. else l=mid+1;
  26. }
  27. ans==-1?puts("No way!"):printf("%lld\n",ans);
  28. }
  29. return 0;
  30. }

算法

根据题意,把边按从小到大的顺序加入结果显然是最优的。
什么时候会形成环?往最小生成树上加边就会形成环。
于是我们先构建一颗最小生成树。
然后从小到大加上非树边。
每加入一条非树边,就可以把路径间所有的点(环)缩成一个环。它们互相之间都有第二条联通路径相互到达,可视为一体。该操作用并查集维护。
具体是将这些点的改变为(最上面那个点)。
如果加上一条非树边边后,发现在同一并查集,就说明他们有了除最小生成树上路径以外的第二条联通路径,满足题意。这条非树边长度就是答案。
复杂度并查集被看作常数复杂度

  1. #include<iostream>
  2. #include<cmath>
  3. #include<cstring>
  4. #include<cstdio>
  5. #include<cstdlib>
  6. #include<algorithm>
  7. #define ll long long
  8. #define re register
  9. #define il inline
  10. #define fp(i,a,b) for(re int i=a;i<=b;i++)
  11. #define fq(i,a,b) for(re int i=a;i>=b;i--)
  12. using namespace std;
  13. const int N=5e5+100;
  14. int n,m,q,h[N],cnt,f[N],d[N],ff[N],vis[N];
  15. ll num[N];
  16. struct Edge
  17. {
  18. int to,nxt;ll w;
  19. }e[N<<1];
  20. struct dat
  21. {
  22. int u,v,vis;ll w;
  23. bool operator < (const dat &o) const {return w<o.w;}
  24. }a[N];
  25. il void add(re int u,re int v,re ll w){e[++cnt].to=v;e[cnt].nxt=h[u];e[cnt].w=w;h[u]=cnt;}
  26. il ll gi()
  27. {
  28. re ll x=0,t=1;
  29. re char ch=getchar();
  30. while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
  31. if(ch=='-') t=-1,ch=getchar();
  32. while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  33. return x*t;
  34. }
  35. il void wri(re int x)
  36. {
  37. if(x<0) putchar('-'),x=-x;
  38. if(x>9) wri(x/10);
  39. putchar(x%10+'0');
  40. }
  41. il int find(re int x){return x==f[x]?x:f[x]=find(f[x]);}
  42. il void dfs(re int u)
  43. {
  44. vis[u]=1;
  45. for(re int i=h[u];i+1;i=e[i].nxt)
  46. {
  47. re int v=e[i].to;
  48. if(vis[v]) continue;
  49. d[v]=d[u]+1;ff[v]=u;
  50. dfs(v);
  51. }
  52. }
  53. int main()
  54. {
  55. freopen("krap.in","r",stdin);
  56. freopen("krap.out","w",stdout);
  57. n=gi();m=gi();q=gi();
  58. memset(h,-1,sizeof(h));
  59. fp(i,1,n) num[i]=gi(),f[i]=i;
  60. fp(i,1,m)
  61. {
  62. re int u=gi(),v=gi();ll w=num[u]-num[v];if(w<0) w=-w;
  63. a[i].u=u,a[i].v=v,a[i].w=w;
  64. }
  65. sort(a+1,a+1+m);
  66. fp(i,1,m)
  67. {
  68. re int u=a[i].u,v=a[i].v,w=a[i].w,fu=find(u),fv=find(v);
  69. if(fu^fv)
  70. {
  71. a[i].vis=1;
  72. f[fv]=fu;
  73. add(u,v,w);add(v,u,w);
  74. }
  75. }
  76. fp(i,1,n) if(!vis[i]) dfs(i);
  77. while(q--)
  78. {
  79. re int uu=gi(),vv=gi();
  80. re ll ans=-1;
  81. fp(i,1,n) f[i]=i;
  82. fp(i,1,m)
  83. if(!a[i].vis)
  84. {
  85. re int u=a[i].u,v=a[i].v,fu=find(u),fv=find(v),pu=fu,pv=fv;
  86. if(fu^fv)
  87. {
  88. while(fu^fv)
  89. {
  90. if(d[fu]<d[fv]) swap(fu,fv);
  91. fu=ff[fu];
  92. }
  93. re int lca=fu;
  94. for(;pu^lca;pu=find(ff[pu])) f[pu]=lca;
  95. for(;pv^lca;pv=find(ff[pv])) f[pv]=lca;
  96. if(find(uu)==find(vv)) {ans=a[i].w;break;}
  97. }
  98. }
  99. ans==-1?puts("No way!"):printf("%lld\n",ans);
  100. }
  101. fclose(stdin);
  102. fclose(stdout);
  103. return 0;
  104. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注