习题:Power Tree(最小生成树&模型转换)

题目

传送门

思路

考虑一种类似于差分的方法

控制一个节点,我们实际上是对他的叶子进行区间加减,如果对叶子进行差分处理,那么一个节点实际上能控制\(l\)\(r+1\)号节点,

比较明显的,如果我们要控制所有节点,那么我们一定要覆盖所有的叶子结点,也就是指我们能自由变换任意区间,很显然的,把一个节点看做一条\(l\)链接\(r+1\)的边,对其跑最小生成树即可

至于所有的方案,就是把某一个权值相同块内的所有点都扫一遍

代码

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
namespace IO
{
    void read(int &x)
    {
        x=0;
        int f=1;
        char c=getchar();
        while('0'>c||c>'9')
        {
            if(c=='-')  
                f=-1;
            c=getchar();
        }
        while('0'<=c&&c<='9')
        {
            x=(x<<3)+(x<<1)+c-'0';
            c=getchar();
        }
        x*=f;
    }
    void read(long long &x)
    {
        x=0;
        int f=1;
        char c=getchar();
        while('0'>c||c>'9')
        {
            if(c=='-')  
                f=-1;
            c=getchar();
        }
        while('0'<=c&&c<='9')
        {
            x=(x<<3)+(x<<1)+c-'0';
            c=getchar();
        }
        x*=f;
    }
    void write(int x)
    {
        if(x<10)
            putchar(x+'0');
        else
        {
            write(x/10);
            putchar(x%10+'0');
        }
    }
    void write(long long x)
    {
        if(x<10)
            putchar(x+'0');
        else
        {
            write(x/10);
            putchar(x%10+'0');
        }
    }
}
namespace ufs
{
    int fa[200005];
    void makeset(int n)
    {
        for(int i=1;i<=n;i++)
            fa[i]=i;
    }
    int findset(int x)
    {
        if(fa[x]==x)
            return x;
        return fa[x]=findset(fa[x]);
    }
    void merge(int u,int v)
    {
        int a=findset(u);
        int b=findset(v);
        fa[a]=b;
    }
}
using namespace IO;
using namespace ufs;
struct node
{
    int u,v;
    long long w;
    int id;
    friend bool operator < (const node &a,const node &b)
    {
        return a.w<b.w;
    }
}a[200005];
int n,lena;
int cnt;
int l[200005],r[200005];
long long w[200005],mst;
vector<int> g[200005];
vector<int> ans;
void dfs(int u,int fa)
{
    if(g[u].size()==1&&g[u].front()==fa)
    {
        l[u]=++cnt;
        r[u]=cnt;
        a[++lena]=(node){l[u],r[u]+1,w[u],u};
        return;
    }
    l[u]=(1<<30);
    r[u]=0;
    for(int i=0;i<g[u].size();i++)
    {
        int v=g[u][i];
        if(v!=fa)
        {
            dfs(v,u);
            l[u]=min(l[u],l[v]);
            r[u]=max(r[u],r[v]);
        }
    }
    a[++lena]=(node){l[u],r[u]+1,w[u],u};
}
int main()
{
    ios::sync_with_stdio(false);
    read(n);
    for(int i=1;i<=n;i++)
        read(w[i]);
    for(int i=1,u,v;i<n;i++)
    {
        read(u);
        read(v);
        g[u].push_back(v);
        g[v].push_back(u);
    }
    dfs(1,0);
    sort(a+1,a+lena+1);
    makeset(n+1);
    for(int i=1,j;i<=lena;i=j)
    {
        j=i;
        while(a[j].w==a[i].w&&j<=lena)
        {
            if(findset(a[j].u)!=findset(a[j].v))
                ans.push_back(a[j].id);
            j++;
        }
        for(int k=i;k<j;k++)
        {
            if(findset(a[k].u)!=findset(a[k].v))
            {
                merge(a[k].u,a[k].v);
                mst+=a[k].w;
            }
        }
    }
    write(mst);
    putchar(' ');
    write((int)ans.size());
    putchar('\n');
    sort(ans.begin(),ans.end());
    for(int i=0;i<ans.size();i++)
    {
        write(ans[i]);
        putchar(' ');
    }   
    return 0;
}
posted @ 2020-08-24 14:39  loney_s  阅读(198)  评论(0)    收藏  举报