hdu6041

题意

给出一个仙人掌

如果一个无向连通图的任意一条边最多属于一个简单环,我们就称之为仙人掌。所谓简单环即不经过重复的结点的环。

求前 \(K\) 小生成树 。

分析

仙人掌中每个环中我们最多可以删掉一条边,题目就变成了有 \(M\) 个数组,每次从每个数组中分别取一个数字并求和,前 \(K\) 大的和。

首先用 \(Tarjan\) 算法找环,然后使用优先队列不断合并两个数组( 多路归并问题,见白书 P189 )。

code

  1. #include<bits/stdc++.h>
  2. typedef long long ll;
  3. using namespace std;
  4. const int MAXN = 1e5 + 10;
  5. const int M = 2e3;
  6. int n, m, K;
  7. struct Edge {
  8. int to, w, next;
  9. }e[M << 1];
  10. int cnt, head[M << 1];
  11. void addedge(int u, int v, int w) {
  12. e[cnt].to = v;
  13. e[cnt].w = w;
  14. e[cnt].next = head[u];
  15. head[u] = cnt++;
  16. }
  17. int a[MAXN], b[MAXN], c[MAXN];
  18. int dfn[M], sz;
  19. stack<int> sta;
  20. struct Item {
  21. int s;
  22. int x;
  23. Item(int s, int x):s(s), x(x) {}
  24. bool operator<(const Item& other) const {
  25. return s < other.s;
  26. }
  27. };
  28. void cal() {
  29. priority_queue<Item> q;
  30. for(int i = 1; i <= b[0]; i++) {
  31. q.push(Item(a[1] + b[i], 2));
  32. }
  33. c[0] = 0;
  34. while(c[0] < K && !q.empty()) {
  35. Item it = q.top(); q.pop();
  36. c[++c[0]] = it.s;
  37. if(it.x <= a[0]) q.push(Item(it.s - a[it.x - 1] + a[it.x], it.x + 1));
  38. }
  39. a[0] = c[0];
  40. for(int i = 1; i <= c[0]; i++) {
  41. a[i] = c[i];
  42. }
  43. }
  44. int tarjan(int fa, int u) {
  45. dfn[u] = ++sz;
  46. int lowu = sz;
  47. for(int i = head[u]; ~i; i = e[i].next) {
  48. int v = e[i].to;
  49. if(!dfn[v]) {
  50. sta.push(i);
  51. int lowv = tarjan(u, v);
  52. if(lowu <= lowv) {
  53. b[0] = 0;
  54. while(1) {
  55. int j = sta.top(); sta.pop();
  56. b[++b[0]] = e[j].w;
  57. if(j == i) break;
  58. }
  59. if(b[0] > 1) cal();
  60. } else lowu = lowv;
  61. } else if(v != fa && lowu > dfn[v]) {
  62. sta.push(i);
  63. lowu = dfn[v];
  64. }
  65. }
  66. return lowu;
  67. }
  68. int main() {
  69. int kase = 1;
  70. while(~scanf("%d%d", &n, &m)) {
  71. while(!sta.empty()) sta.pop();
  72. cnt = 0;
  73. sz = 0;
  74. memset(dfn, 0, sizeof dfn);
  75. memset(head, -1, sizeof head);
  76. a[0] = 1; a[1] = 0;
  77. int s = 0;
  78. for(int i = 0; i < m; i++) {
  79. int u, v, w;
  80. scanf("%d%d%d", &u, &v, &w);
  81. s += w;
  82. addedge(u, v, w);
  83. addedge(v, u, w);
  84. }
  85. scanf("%d", &K);
  86. tarjan(-1, 1);
  87. unsigned ans = 0;
  88. for(int i = 1; i <= a[0]; i++) {
  89. ans = ans + (unsigned)i * (s - a[i]);
  90. }
  91. if(a[0] == 0) ans = s;
  92. printf("Case #%d: %u\n", kase++, ans);
  93. }
  94. return 0;
  95. }

hdu6041的更多相关文章

随机推荐

  1. BZOJ_day4&&DSFZ_day1

    昨天坐火车才水了三道题... 25题 100810221041105110591087108811791191119212571303143218541876195119682140224224382 ...

  2. oracle的group by问题

    ORA-00979 不是 GROUP BY 表达式”这个错误,和我前面介绍的另外一个错误ORA-00937一样使很多初学oracle的人爱犯的. 我在介绍使用聚合函数中用group by来分组数据时特 ...

  3. 7月24号day16总结

    一开始显示出现问题,js路径不能应用,因为用的是springMVC框架书写,所以有路径的保护和静态引用地址时需要注意的地方 今天进行了最后项目的优化,包括map清洗数据部分的代码和echarts显示的 ...

  4. JS 中 call 和 apply 的理解和使用

    本文受到了知乎问题 如何理解和熟练运用js中的call及apply? 的启发. obj.call(thisObj, arg1, arg2, ...); obj.apply(thisObj, [arg1 ...

  5. MyBatis的SQL语句映射文件详解

    SQL 映射XML 文件是所有sql语句放置的地方.需要定义一个workspace,一般定义为对应的接口类的路径.写好SQL语句映射文件后,需要在MyBAtis配置文件mappers标签中引用 < ...

  6. HDU1099---数学 | 思维

    hdu 1099 Lottery题意:1~n编号的彩票,要买全,等概率条件下平均要买几张.已经买了m张时,买中剩下的概率为1-m/n,则要买的张数为1/(1-m/n)n=2,s=1+1/(1-1/2) ...

  7. PHP文件操作函数二

    PHP部分文件访问函数总结: 1.filetype("文件路径")  //可以输出相关文件类型,返回之为:dir/file... 2.stat("文件名") / ...

  8. 【Foreign】最大割 [线性基]

    最大割 Time Limit: 15 Sec  Memory Limit: 256 MB Description Input Output Sample Input 3 6 1 2 1 1 2 1 3 ...

  9. sql 批量更新表中多字段为不同的值

    ,),,),rand()) select newid() ,) update tablename , FB,)) , ), FC,)) , )

  10. Nginx的主要配置参数说明

    #定义Nginx运行的用户和用户组user www www; #nginx进程数,建议设置为等于CPU总核心数.worker_processes 8; #全局错误日志定义类型,[ debug | in ...