• Codeforces 1247F. Tree Factory


    传送门

    正难则反,把链操作成树不好想,那么考虑一下如何把树变成链

    每次操作相当于把一个兄弟变成儿子(我把你当兄弟你竟然想把我当儿子.jpg)

    注意到每次操作最多只能使树的深度增加 $1$

    因为链的深度为 $n$ 且形态唯一,那么只要把原树操作成深度为 $n$ 即可

    现在得到了一个操作次数的下限,即 $n$ 减树的初始深度

    考虑一下如果每次操作都能保证使树的深度增加,那么这样的一系列操作即为最优答案

    事实上任何时刻都一定存在可以使长度增加的操作,考虑当前树从根节点出发的最长链,我们找到链上最深的存在分叉的节点 $x$

    设 $v$ 为 $x$ 的儿子且在最长链上,$w$ 为 $x$ 的任意一个其他儿子,那么我们只要把 $v$ 变成 $w$ 的儿子即可使树深度增加

    显然当树的深度不为 $n$ 时,最长链上一定存在分叉

    然后现在问题就是输出方案了,这个东西不太好解释,看代码比较清楚吧...(代码很短)

    注意一下代码实现的时候是链变成树而不是树变成链了

    代码参考:wxhtxdy

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<vector>
    using namespace std;
    typedef long long ll;
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    const int N=1e5+7;
    int n,fa[N],dep[N],son[N];
    vector <int> V[N],id,mov;
    int cnt;//这个东西表示当前节点上一个兄弟的最后一条链的深度
    void dfs(int x)
    {
        id.push_back(x);
        for(int i=1;i<=cnt;i++) mov.push_back(x);
        cnt=0;
        for(int v: V[x]) if(v!=son[x]) dfs(v);
        if(son[x]) dfs(son[x]);//最长链最后走
        cnt++;
    }
    int main()
    {
        n=read(); dep[1]=1;
        for(int i=2;i<=n;i++)
        {
            int a=read()+1; fa[i]=a;
            dep[i]=dep[a]+1; V[a].push_back(i);
        }
        int t=max_element(dep+1,dep+n+1)-dep;
        while(t!=1) son[fa[t]]=t,t=fa[t];//找最长链
        dfs(1);
        for(int x: id) printf("%d ",x-1); puts("");
        printf("%d
    ",int(mov.size()));
        for(int x: mov) printf("%d ",x-1); puts("");
        return 0;
    }
  • 相关阅读:
    3.27上午
    3.24上午 补
    2017.3.27下午
    2017.3.27上午
    2017.3.24下午
    2017.3.24上午
    2017.3.23下午
    2017.3.23上午
    2017.3.22上午
    2017.3.21下午
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/11750250.html
Copyright © 2020-2023  润新知