Educational Codeforces Round 35 (Rated for Div. 2) F Tree Destruction

29 篇文章 0 订阅
6 篇文章 0 订阅

题目链接:点击打开链接

题意:给一棵树(n个顶点,n-1条边),初始化一个值为0,每次选择树中两个顶点并删去其中一个,并加这两点的路径长加到该值上,直到删完所有边,求该值达到最大时的操作顺序和该值大小。

思路:找出树的直径,并对直径外的点从外到内依次删除(这里我粗暴的用了排序,路径长大的先输出,可优化),最后从直径的一个端点依次删除直径上的其他点,这样就能达到最大值。

AC代码如下:(950鶸T)

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>

using namespace std;

int n;
vector<vector<int>> tree;

int record[200005];
int flag[200005];
int relen[3][200005];
int be, en, mid;
long long maxw;

struct an{
    int a, b;
    int dis;
    an(int a, int b, int c):a(a),b(b),dis(c) {}
};

bool operator <(an& a, an& b)
{
    return a.dis>b.dis;
}

vector<an>  anset;

int flw(int v)
{
    memset(flag,0,sizeof(int)*n+1);
    flag[v] = 1;

    long long tempw = 0;
    queue<int> re;  re.push(v);
    while(1)
    {
        int s = re.size();
        int tt = re.front();
        for(int i=0;i<s;++i)
        {
            tt = re.front();
            for(int i=0;i<tree[tt].size();++i)
                if(flag[tree[tt][i]] == 0)
                {
                    flag[tree[tt][i]] = 1;
                    re.push(tree[tt][i]);
                }
            re.pop();
        }
        if(re.empty())  {maxw = max(maxw,tempw);    return tt;}
        else    tempw++;
    }
}


void fds(int root, int num)
{
    queue<int> re;
    re.push(root);
    memset(flag,0,sizeof(flag));
    flag[root] = 1;
    re.push(root);
    while(!re.empty())
    {
        int s = re.size();
        for(int i=0;i<s;++i)
        {
            int tt = re.front();
            for(int i=0;i<tree[tt].size();++i)
            {
                if(!flag[tree[tt][i]])
                {
                    relen[num][tree[tt][i]] = relen[num][tt] + 1;
                    flag[tree[tt][i]] = 1;
                    re.push(tree[tt][i]);
                }
            }
            re.pop();
        }
    }
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    for(int i=0;i<200000;++i)
    {
        vector<int> temp;
        tree.push_back(temp);
    }
    while(cin>>n)
    {
        maxw = -1;
        for(int i=0;i<n;++i)
            tree[i].clear();
        for(int i=0;i<n-1;++i)
        {
            int a, b;
            cin>>a>>b;
            tree[a].push_back(b);
            tree[b].push_back(a);
        }
        be = flw(1);
        en = flw(be);
        long long ans = maxw*(maxw+1)/2;
        relen[1][be] = relen[2][en] = 0;
        fds(be,1);
        fds(en,2);
        anset.clear();
        for(int i=1;i<=n;++i)
        {
            int a = relen[1][i];
            int b = relen[2][i];
            if(a+b != maxw)
            {
                if(a>b) {ans+=a;  anset.push_back(an(be,i,a)); }
                else    {ans+=b;  anset.push_back(an(en,i,b));  }
            }
            else    record[a] = i;
        }
        sort(anset.begin(),anset.end());
        cout<<ans<<endl;
        for(int i=0;i<anset.size();++i)
        {
            cout<<anset[i].a<<" "<<anset[i].b<<" "<<anset[i].b<<endl;
        }
        for(int i=maxw;i>=1;--i)
        {
            cout<<be<<" "<<record[i]<<" "<<record[i]<<endl;
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值