经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C » 查看文章
cf160D. Edges in MST(最小生成树 桥)
来源:cnblogs  作者:自为风月马前卒  时间:2018/10/18 9:03:43  对本文有异议

题意

题目链接

给出一棵树,确定每条边状态: 一定在MST上 / 可能在MST上 / 不可能在MST上

\(n \leqslant 10^5, m \leqslant 10^5\)

Sol

MST表示最小生成树

表示只能想到\(nlog^2n\)的做法:先求出MST。然后枚举剩下的边,如果权值出现在形成的环上,那么该边和MST上的边都是可能出现,如果权值大于环上最大值,那么该边不可能在MST上。没有被标记过的边一定在MST上。

树剖+主席树维护一下。。

标算好神仙啊。

结论:将任意两个MST上的边排序后,得到的序列是相同的

自己xjbYY的证明:

反证法。

若不满足条件,则两个序列中一定存在四个位置

\(x_1, y_1\)

\(x_2, y_2\)

满足\(x_1 < x_2\)\(y_1 > y_2\)。(如果只有一个不同的话权值大的不会成为MST)

那么把\(x_1\)加入到第二个MST中,同时删去环上最大的边,会得到一个权值更小的MST。

哎,自己还想到这里了,不过立马就否决了。。

首先排序,对权值相同的边一起考虑。如果当前边所连的联通块已经被合并,那么该边一定不在MST上。这样就解决了第三种情况

考虑剩下的边,要么一定在MST上,要么可能在MST上。

如果一定在MST上,显然断开它之后会形成两个联通块。这与“桥”的定义相同!所以tarjan一遍求出所有桥就行了。

如果每次都tarjan的话显然会T飞,因此我们把在一个联通块内的点缩起来就行了

  1. #include<bits/stdc++.h>
  2. #define Pair pair<int, int>
  3. #define MP(x, y) make_pair(x, y)
  4. #define fi first
  5. #define se second
  6. using namespace std;
  7. const int MAXN = 2e5 + 10;
  8. inline int read() {
  9. char c = getchar(); int x = 0, f = 1;
  10. while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
  11. while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
  12. return x * f;
  13. }
  14. int N, M;
  15. vector<Pair> v[MAXN];
  16. struct Edge {
  17. int u, v, w, f, id;
  18. bool operator < (const Edge &rhs) const {
  19. return w < rhs.w;
  20. }
  21. }E[MAXN];
  22. int dfn[MAXN], low[MAXN], tot, fa[MAXN], ans[MAXN];
  23. void tarjan(int x, int fa) {//这里的fa表示边的编号
  24. dfn[x] = low[x] = ++tot;
  25. for(int i = 0, to, id; i < v[x].size(); i++) {
  26. if((id = v[x][i].se) == fa) continue;
  27. to = v[x][i].fi;
  28. if(!dfn[to]) {
  29. tarjan(to, id), low[x] = min(low[x], low[to]);
  30. if(low[to] > dfn[x]) E[id].f = 2;
  31. }
  32. else low[x] = min(low[x], dfn[to]);
  33. }
  34. }
  35. int find(int x) {
  36. return x == fa[x] ? fa[x] : fa[x] = find(fa[x]);
  37. }
  38. int main() {
  39. N = read(), M = read();
  40. for(int i = 1; i <= N; i++) fa[i] = i;
  41. for(int i = 1; i <= M; i++) {
  42. int x = read(), y = read(), z = read();
  43. E[i] = (Edge) {x, y, z, 0, i};
  44. }
  45. sort(E + 1, E + M + 1);
  46. int nxt;
  47. for(int i = 1; i <= M; i = nxt + 1) {
  48. nxt = i + 1;
  49. for(; E[i].w == E[nxt].w; nxt++); nxt--;
  50. for(int j = i; j <= nxt; j++) {
  51. int x = find(E[j].u), y = find(E[j].v);
  52. if(x == y) continue;
  53. v[x].push_back(MP(y, j));
  54. v[y].push_back(MP(x, j));
  55. E[j].f = 1;//maybe
  56. }
  57. for(int j = i; j <= nxt; j++) {
  58. int x = find(E[j].u), y = find(E[j].v);
  59. if(x == y || dfn[x]) continue;
  60. tarjan(x, -1);
  61. }
  62. for(int j = i; j <= nxt; j++) {
  63. int x = find(E[j].u), y = find(E[j].v);
  64. if(x == y) continue;
  65. v[x].clear(); v[y].clear();
  66. dfn[x] = 0; dfn[y] = 0;
  67. fa[x] = y;
  68. }
  69. }
  70. for(int i = 1; i <= M; i++) ans[E[i].id] = E[i].f;
  71. for(int i = 1; i <= M; i++) {
  72. if(ans[i] == 0) puts("none");
  73. else if(ans[i] == 1) puts("at least one");
  74. else puts("any");
  75. }
  76. return 0;
  77. }
  78. /*
  79. */
 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号