1. 程式人生 > >CF911F Tree Destruction 解題報告

CF911F Tree Destruction 解題報告

ply apply amp strong 結果 next clas truct 情況

CF911F Tree Destruction

題意翻譯

給你一棵樹,每次挑選這棵樹的兩個葉子,加上他們之間的邊數(距離),然後將其中一個點去掉,問你邊數(距離)之和最大可以是多少.

輸入輸出格式

輸入格式:

The first line contains one integer number n \(n\) ( \(2 \le n \le 2 \times 10^{5}\) ) — the number of vertices in the tree.

Next \(n-1\) lines describe the edges of the tree in form \(a_{i}\),\(b_{i}\)

( \(1<=a_{i}\), \(b_{i}<=n\) , \(a_{i} \not= b_{i}\) ). It is guaranteed that given graph is a tree.

輸出格式:

In the first line print one integer number — maximal possible answer.

In the next \(n-1\) lines print the operations in order of their applying in format \(a_{i},b_{i},c_{i}\) , where \(a_{i},b_{i}\)

— pair of the leaves that are chosen in the current operation ( \(1 \le a_{i}\) ,\(b_{i} \le n\) ), \(c_{i}\) ( \(1 \le c_{i} \le n\) , \(c_{i}=a_{i}\) or \(c_{i}=b_{i}\) ) — choosen leaf that is removed from the tree in the current operation.

See the examples for better understanding.


給了一個貪心的思路:不會產生比最好情況下還要差的結果(由最優推最優)

首先如果只有一條鏈,答案是很顯然的。

如果鏈外有點,點到鏈的某個端點一定是所有情況的最優貢獻,並且刪去鏈外的點對鏈本身沒有影響。

所以策略就是找到直徑的那條鏈,一個一個刪外面的點,最後刪直徑的。


Code:

#include <cstdio>
#define ll long long
const int N=2e5+10;
int Next[N<<1],to[N<<1],head[N],cnt;
void add(int u,int v)
{
    to[++cnt]=v,Next[cnt]=head[u],head[u]=cnt;
}
int mx=-1,l,r;
void dfs1(int now,int fa,int d)
{
    if(mx<d) mx=d,l=now;
    for(int i=head[now];i;i=Next[i])
    {
        int v=to[i];
        if(v!=fa)
            dfs1(v,now,d+1);
    }
}
int pre[N];
void dfs2(int now,int fa,int d)
{
    if(mx<d) mx=d,r=now;
    for(int i=head[now];i;i=Next[i])
    {
        int v=to[i];
        if(v!=fa)
            pre[v]=now,dfs2(v,now,d+1);
    }
}
ll sum;
int ans[N][2],is[N],n,opt;
void dfs0(int now,int fa,int d,int s)
{
    for(int i=head[now];i;i=Next[i])
    {
        int v=to[i];
        if(is[v]||v==fa) continue;
        dfs0(v,now,d+1,s);
    }
    if(!is[now]) ans[++opt][0]=now,ans[opt][1]=s,sum+=1ll*d;
}
int main()
{
    scanf("%d",&n);
    for(int u,v,i=1;i<n;i++)
    {
        scanf("%d%d",&u,&v);
        add(u,v),add(v,u);
    }
    dfs1(1,0,0);
    mx=-1;
    dfs2(l,0,0);
    int now=r,cnt1=0,cnt0=0;
    while(now)
        ++cnt1,is[now]=1,now=pre[now];
    now=r;
    while(now)
    {
        ++cnt0;
        if(((cnt0-1)<<1)>cnt1-1)
            dfs0(now,0,cnt0-1,r);
        else
            dfs0(now,0,cnt1-cnt0,l);

        now=pre[now];
    }
    now=r,cnt0=0;
    while(now)
    {
        ++cnt0;
        ans[++opt][0]=now,ans[opt][1]=l,sum+=1ll*(cnt1-cnt0);
        now=pre[now];
    }
    printf("%lld\n",sum);
    for(int i=1;i<n;i++)
        printf("%d %d %d\n",ans[i][0],ans[i][1],ans[i][0]);
    return 0;
}

2018.10.11

CF911F Tree Destruction 解題報告