考虑把树展开,单独把叶子节点拿出来

于是可以把控制点\(x\)的,抽象成是在它叶子节点间连权值为\(c_x\)的边

显然只用在\(x\)子树的最左边的叶子节点和最右边的叶子节点的下一个节点连边(最后一个叶子节点的下一个节点为 \(n+1\)),跑最小生成树即可

正确性证明的话,设叶子节点的权值分别为\(x_1,x_2……x_n\),做差分\(y_i=x_{i+1}-x_i\),显然\(\sum \limits _{i=1}^n y_i =0\)

正确性的话,感性理解一下吧QAQ,有理有据的感性理解

代码:

//OwO
#include <bits/stdc++.h>
#define N 200010
#define rep(i,x,y) for(i=x;i<=y;++i)
#define add(x,y) g[x].push_back(y)
#define ll long long
#define pii pair<int,int>
using namespace std;

ll c[N];
int dfn[N],sz[N],cnt,tot,fa[N],qwq[N],l[N],r[N],rr[N],n,lf=0;
vector<int> g[N];
struct ed{
    int u,v,p;
    ll w;
    bool operator <(const ed &x)const{ return w<x.w; }
}e[N];
void ADD(int u,int v,int p,ll w){ e[++cnt]=(ed){u,v,p,w}; }

pii dfs(int x,int fa){
    pii lst;
    int pl=0;
    if(g[x].size()<=1 && x!=1) l[x]=r[x]=++lf;
    for(int i=0;i<g[x].size();++i){
        int to=g[x][i];
        if(to!=fa){
            pii tmp=dfs(to,x);
            l[x]=min(l[x],tmp.first);
            r[x]=max(r[x],tmp.second);
        }
    }
    return make_pair(l[x],r[x]);
}

int find(int x){ return (fa[x]==x)?x:fa[x]=find(fa[x]); }

ll solve1(){
    int i;ll ans=0;
    rep(i,1,cnt){
        int u=find(e[i].u),v=find(e[i].v);
        if(u==v) continue;
        if(u>v) swap(u,v);
        fa[v]=u;
        ans+=e[i].w;
    }
    return ans;
}

void solve2(){
    int i,nxt,j;tot=0;
    rep(i,1,n+1) fa[i]=i;
    for(i=1;i<=cnt;i=nxt){
        for(j=i;e[j].w==e[i].w;++j){
            int u=find(e[j].u),v=find(e[j].v);
            if(u!=v) qwq[++tot]=e[j].p;
        }
        nxt=j;
        for(j=i;e[j].w==e[i].w;++j){
            int u=find(e[j].u),v=find(e[j].v);
            if(u>v) swap(u,v);
            if(u!=v) fa[v]=u;
        }
    }
}

int main(){
    int i,x,y;
    scanf("%d",&n);
    rep(i,1,n) scanf("%I64d",&c[i]),fa[i]=i;fa[n+1]=n+1;
    rep(i,1,n-1){
        scanf("%d%d",&x,&y);
        add(x,y),add(y,x);
    }
    memset(l,0x3f,sizeof(l));
    memset(r,0,sizeof(r));
    dfs(1,0);rr[1]=n+1;
    rep(i,1,n) ADD(l[i],r[i]+1,i,c[i]);
    sort(e+1,e+cnt+1);
    cout<<solve1()<<" ";
    solve2();
    sort(qwq+1,qwq+tot+1);
    cout<<tot<<endl;
    rep(i,1,tot) printf("%d ",qwq[i]);
}

CF1120D(神奇的构造+最小生成树)的更多相关文章

  1. Kruskal算法构造最小生成树

    Kruskal算法来构造最小生成树,我总结了分为以下步骤: (1)建图,构造Kruskal边集,边集元素应该包括该边的起始顶点.终止顶点.权值: (2)将边集按权值从小到大的顺序进行排序: (3)从小 ...

  2. c/c++ 用克鲁斯卡尔(kruskal)算法构造最小生成树

    c/c++ 用克鲁斯卡尔(kruskal)算法构造最小生成树 最小生成树(Minimum Cost Spanning Tree)的概念: 假设要在n个城市之间建立公路,则连通n个城市只需要n-1条线路 ...

  3. c/c++ 用普利姆(prim)算法构造最小生成树

    c/c++ 用普利姆(prim)算法构造最小生成树 最小生成树(Minimum Cost Spanning Tree)的概念: ​ 假设要在n个城市之间建立公路,则连通n个城市只需要n-1条线路.这时 ...

  4. 图的建立(邻接矩阵)+深度优先遍历+广度优先遍历+Prim算法构造最小生成树(Java语言描述)

    主要参考资料:数据结构(C语言版)严蔚敏   ,http://blog.chinaunix.net/uid-25324849-id-2182922.html   代码测试通过. package 图的建 ...

  5. MST性质(用于构造最小生成树)

    描述:假设N=(V,{E})是一个连通网,U是顶点集V的一个非空子集.若(u,v)是一条具有最小权值(代价)的边,其中u∈U,v∈V-U,则必存在一棵包含边(u,v)的最小生成树. 证明: 假设网N的 ...

  6. 数据结构-图-Java实现:有向图 图存储(邻接矩阵),最小生成树,广度深度遍历,图的连通性,最短路径1

    import java.util.ArrayList; import java.util.List; // 模块E public class AdjMatrixGraph<E> { pro ...

  7. CSU 1116 Kingdoms(枚举最小生成树)

    题目链接:http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1116 解题报告:一个国家有n个城市,有m条路可以修,修每条路要一定的金币,现在这个国家只 ...

  8. poj1251 最小生成树

    Description The Head Elder of the tropical island of Lagrishan has a problem. A burst of foreign aid ...

  9. ACM: meixiuxiu学图论-并查集-最小生成树-解题报告

    /* 最小生成树,最小环的最大权值按照排序后去构建最小生成树就可以了,注意遇到的第一个根相同的点就记录权值,跳出,生成的环就是最小权值环. */ //AC代码: #include"iostr ...

随机推荐

  1. 通过Excel文件快速创建页面和数据表

    在设计一个软件系统,构建过程:需求->数据表->系统开发.实际情况是需求(数据)很多来源于已经存在的文件中,客户会要求把这些数据“电子化”,这就给需求分析产生了很大的工作量: 分析这些原始 ...

  2. Fragment与Activity的接口回调

    这里说一个官方推荐的写法: private OnFragmentInteractionListener mListener; @Override public void onAttach(Contex ...

  3. 自定义Progress小控件

    progress各种各样的都有,自定义大多数也是简单的,根据业务需求来自己定义,记录一下,先上效果图 本来想找个第三方改改就上的,不过自己的业务需求有点不搭,一下子没找到合适的,也没这么多时间去找了, ...

  4. 基础环境系列:MySQL8.0.12

    机型与版本:windows10(64-bits) Mysql环境配置:mysql8.0.12 一.MySQL安装 Mysql的安装有两种方法,一种是通过.msi一种是通过压缩包.穷呢,大家就老实下社区 ...

  5. 利用ZYNQ SOC快速打开算法验证通路(5)——system generator算法IP导入IP integrator

    一.前言 利用FPGA设计算法一直以来都是热点,同样也是难点.将复杂的数学公式 模型通过硬件系统来搭建,在低延时 高并行性等优势背后极大提高了设计难度和开发周期.Xilinx公司的sysGen(sys ...

  6. linux-arm 安装 dotnetcore

    X86或者X64 安装.net core runtime  可以参照   https://www.cnblogs.com/nnhy/p/netcore_centos.html#4122354 而   ...

  7. Thinkphp volist 多重循环原样输出数组key值的使用总结

    最近因为项目的缘故,要使用到volist.在这个过程中,遇到了一些小问题,主要就是volist在循环输出多重数据的时候,如何输出key.网上查阅了不少资料,很失望的是,大多资料就是粘贴复制Thinkp ...

  8. Bootstrap -- 下拉菜单、输入框组、导航菜单

    Bootstrap -- 下拉菜单.输入框组.导航菜单 1. 下拉菜单 可以使用带有各种大小按钮的下拉菜单:.btn-lg..btn-sm 或 .btn-xs. 实现下拉菜单: <!DOCTYP ...

  9. LeetCode算法题-Diameter of Binary Tree(Java实现)

    这是悦乐书的第257次更新,第270篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第124题(顺位题号是543).给定二叉树,您需要计算树的直径长度. 二叉树的直径是树中 ...

  10. 码农人生——从未学过Android如何开发Android App 案例讲解-第002期案例

    标题有点晃眼,本次分享是002期博文的实践故事,不会有任何代码.也不会教别人android 如何开发,类似博文已经有大批大批,而且还会有陆陆续续的人写,我写的文章,主要是经验之谈,希望总结出的一些方法 ...