首页 > 代码库 > Codeforces Round #389 (Div. 2) 752F(树的权值重心)

Codeforces Round #389 (Div. 2) 752F(树的权值重心)

题目大意

给定2k个队伍分别住在2k个城市里,需要设定若干个城市,然后选取2个队伍要在它们的最短路径上设一个城市作为休息站

要求设立最少的休息站,然后输出如何安排2个队伍

 

首先若干个其实就是在坑人,实际上1个就可以了

这一个点就是树的权值重心。

权值重心的定义:若选取权值重心为根,则它的任意子树的权值和不会大于所有子树权值和的二分之一

那么接下来证明权值重心是可行的

只需要构造出来一组分组即可

我是这么构造的

先搜每一个子树,搜集齐k个点放到A,然后继续搜集剩下的点放到B,如果权值重心上也有队伍,那么就把它加到B

然后依次输出A[i],B[i]即可

这样做是可行的,因为任意子树的权值和不会大于所有子树权值和的二分之一。(稍微想想就可以知道啦)

 

#include <iostream>
#include <vector>
#include <queue>
using namespace std;
const int maxn = 222222;
vector<int> G[maxn];
queue<int> Q[2];
int f[maxn], v[maxn], sz[maxn], son[maxn];
int n, k, x, y, X;

void dfs(int x, int fa)
{
    for(int i = 0; i < G[x].size(); i++)
    {
        int to = G[x][i];
        if(fa == to) continue;
        dfs(to, x);
        sz[x] += sz[to];
        son[x] = max(son[x], sz[to]);
    }
    son[x] = max(son[x], 2*k - sz[x]);
}

void dfs2(int x, int fa, int c)
{
    if(!f[x] && Q[c-1].size() < k && v[x])
    {
        f[x] = c;
        Q[c-1].push(x);
    }
    for(int i = 0; i < G[x].size(); i++)
    {
        int to = G[x][i];
        if(fa == to) continue;
        dfs2(to, x, c);
    }
}

int main()
{
    cin>>n>>k;
    for(int i = 1; i < n; i++)
    {
        cin>>x>>y;
        G[x].push_back(y);
        G[y].push_back(x);
    }
    for(int i = 1; i <= 2*k; i++) cin>>x, sz[x] = v[x] = 1;
    dfs(1, 0);
    for(int i = 1; i <= n; i++)
        if(son[i] <= k) X = i;
    cout<<1<<endl<<X<<endl;
    for(int i = 0; i < G[X].size(); i++)
    {
        if(Q[0].size() < k)
            dfs2(G[X][i], X, 1);
        if(Q[0].size() == k)
            dfs2(G[X][i], X, 2);
    }
    if(Q[1].size() == k-1) Q[1].push(X);
    while(!Q[0].empty())
    {
        cout<<Q[0].front()<<" "<<Q[1].front()<<" "<<X<<endl;
        Q[0].pop(); Q[1].pop();
    }
}

 

Codeforces Round #389 (Div. 2) 752F(树的权值重心)