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;}
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 孩子之间发生争执怎么办 被打耳光后耳鸣怎么办 被打了耳鸣怎么办 打到鼻子流鼻血怎么办 一岁多宝宝有痰怎么办 一岁半咳嗽有痰怎么办 12岁说话不清楚怎么办 梦见前夫打孩子怎么办 小儿咳嗽带痰怎么办 孩子扁桃体发炎咳嗽怎么办 一岁宝宝总有痰怎么办 四岁宝宝总有痰怎么办 5岁宝宝总有痰怎么办 一岁宝宝有痰咳不出怎么办 三岁宝宝有痰咳不出怎么办 孩子不听话打她怎么办 孩子笨上学吃力怎么办 孩子学习就睡着怎么办 孩子对父母大喊大叫怎么办 老师面对熊孩子怎么办 妈妈故意打孩子怎么办 老是被妈妈打怎么办 父母老打骂孩子怎么办 后妈总是欺负我怎么办 小朋友屁股被打紫了怎么办 儿童被咬出血怎么办 小宝宝蚊子咬了怎么办 幼儿被咬了怎么办 把孩子屁股肿打紫怎么办 小孩老是咬小孩怎么办 宝宝对蚊子过敏怎么办 胳膊打红了怎么办 孩子生气摔东西怎么办 爱发脾气摔东西怎么办 宝宝生气扔东西怎么办 人流后屁股疼怎么办 生孩子后膝盖痛怎么办 怀孕初期生气了怎么办 孕晚期天天生气怎么办 孩子拉肚子屁股红怎么办 孩子的屁股红怎么办