HDU
来源:互联网 发布:数据透视表刷新数据 编辑:程序博客网 时间:2024/06/05 11:32
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6074
题目大意:Q住在节点1,他想要连电话线,而在S(ai,bi)∪S(ci,di)之中的任意两个节点都可以连接一条电话线,花费为w,问连得最多节点的最小花费是多少
解题思路:问题转换一下就是让图连通的最小花费是多少,这就转化成好了最小生成树的问题,我们先根据w值排序,处理出S(ai,bi)最小生成树,再出理出S(ci,di)的最小生成树,再把两个合并,但是在他们各自处理的过程中,为了避免S(ai,bi)和S(ci,di)可能部分重合的情况,可以在处理过程中,把S(ai,bi)的所有节点都指向lca(ai,bi),那么在处理S(ci,di)时,发现其中某个点指向的点的深度大于lca(ci,di),那么这个点就是处理过的,就不处理。关于Lca树链剖分法,可以参考http://blog.csdn.net/nightmare_ak/article/details/77164374
AC代码:
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;typedef long long LL;const int MAXN = 100000 + 5;struct Edge{ int v, next; Edge(int v = 0, int next = 0) :v(v), next(next) {}}edge[MAXN << 1];struct Node{ int a, b, c, d; LL w; Node(int a = 0, int b = 0, int c = 0, int d = 0, LL w = 0) :a(a), b(b), c(c), d(d), w(w) {} bool operator<(const Node& a)const { return w < a.w; }}node[MAXN];int son[MAXN], bulk[MAXN], dep[MAXN], ft[MAXN], top[MAXN];//求lcaint head[MAXN], edgenum;//链接表int anc[MAXN], tag[MAXN];//最小生成树int cnt[MAXN];//答案储存LL cost[MAXN];void toInit(int n){ edgenum = 0; for (int i = 1;i <= n;++i) { anc[i] = tag[i] = i; cnt[i] = 1;//memset只能处理-1,0 cost[i] = 0; head[i] = -1; }}void toAdd(int u, int v){ edge[edgenum] = Edge(v, head[u]); head[u] = edgenum++;}void toDfs1(int u, int f, int tier){ son[u] = 0;dep[u] = tier;ft[u] = f;bulk[u] = 1; for (int i = head[u];i != -1;i = edge[i].next) { int v = edge[i].v; if (v == f) continue; toDfs1(v, u, tier + 1); bulk[u] += bulk[v]; if (bulk[v] > bulk[son[u]]) son[u] = v; }}void toDfs2(int u, int f, int rt){ top[u] = rt; for (int i = head[u];i != -1;i = edge[i].next) { int v = edge[i].v; if (v == f) continue; if (v == son[u]) toDfs2(v, u, rt); else toDfs2(v, u, v); }}int toLca(int x, int y){ while (top[x] != top[y]) { if (dep[top[x]] < dep[top[y]]) swap(x, y); x = ft[top[x]]; } return dep[x] < dep[y] ? x : y;}int toFind(int x,int F[]){ return F[x] == x ? x : F[x] = toFind(F[x], F);}void toUnion(int x, int y, LL w){ x = toFind(x, anc); y = toFind(y, anc); if (x != y) { anc[y] = x; cost[x] += cost[y] + w; cnt[x] += cnt[y]; }}void toSolve(int r, int x, LL w){ while (1) { x = toFind(x, tag); if (dep[x] <= dep[r])//判断x是否已经合并过 break; toUnion(x, ft[x], w); tag[x] = ft[x];//不断地向祖先r合并 }}void divideCal(int x, int y, LL w){ int r = toLca(x, y); toSolve(r, y, w); toSolve(r, x, w);}int main(){ int t;scanf("%d", &t); while (t--) { int n, m; scanf("%d%d", &n, &m); toInit(n); for (int i = 1;i <= n - 1;++i) { int u, v; scanf("%d%d", &u, &v); toAdd(u, v); toAdd(v, u); } toDfs1(1, 1, 1); toDfs2(1, 1, 1); for (int i = 0;i < m;++i) scanf("%d%d%d%d%I64d", &node[i].a, &node[i].b, &node[i].c, &node[i].d, &node[i].w); sort(node, node + m); for (int i = 0;i < m;++i) { divideCal(node[i].a, node[i].b, node[i].w); divideCal(node[i].c, node[i].d, node[i].w); toUnion(node[i].a, node[i].c, node[i].w); } int k = toFind(1, anc); printf("%d %I64d\n", cnt[k], cost[k]); } return 0;}
阅读全文
0 0
- hdu
- hdu
- HDU
- hdu ()
- hdu
- hdu
- HDU
- HDU
- hdu
- hdu
- HDU
- Hdu
- hdu
- hdu-
- hdu
- hdu
- hdu
- HDU
- SPOJ 705
- Oracle之where子句和order by子句
- JS 之排序算法和去重复算法
- python-PIL 画出带有角度的椭圆
- Linux用户深度管理
- HDU
- Ubuntu 14.04 下 Virtual Judge 的搭建
- java反射机制
- Ubuntu安装VMware-tools步骤
- 20170814
- BUAA OJ 701 DH的矩阵游戏
- 第一次踏入博客的的世界,CSDN,但愿能够坚持下来吧
- [BZOJ3393]二叉树
- EffectiveC++学习笔记-条款47