CF1120D(神奇的构造+最小生成树)

时间:2021-02-01 23:59:22

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

于是可以把控制点\(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]);
}