Codeforces-980E:The Number Games(倍增)

E. The Number Games
time limit per test
3 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

The nation of Panel holds an annual show called The Number Games, where each district in the nation will be represented by one contestant.

The nation has nn districts numbered from 11 to nn, each district has exactly one path connecting it to every other district. The number of fans of a contestant from district ii is equal to 2i2i.

This year, the president decided to reduce the costs. He wants to remove kk contestants from the games. However, the districts of the removed contestants will be furious and will not allow anyone to cross through their districts.

The president wants to ensure that all remaining contestants are from districts that can be reached from one another. He also wishes to maximize the total number of fans of the participating contestants.

Which contestants should the president remove?

Input

The first line of input contains two integers nn and kk (1k<n1061≤k<n≤106) — the number of districts in Panel, and the number of contestants the president wishes to remove, respectively.

The next n1n−1 lines each contains two integers aa and bb (1a,bn1≤a,b≤naba≠b), that describe a road that connects two different districts aaand bb in the nation. It is guaranteed that there is exactly one path between every two districts.

Output

Print kk space-separated integers: the numbers of the districts of which the contestants should be removed, in increasing order of district number.

Examples
input
Copy
6 3
2 1
2 6
4 2
5 6
2 3
output
Copy
1 3 4
input
Copy
8 4
2 6
2 7
7 8
1 2
3 1
2 4
7 5
output
Copy
1 3 4 5
Note

In the first sample, the maximum possible total number of fans is 22+25+26=10022+25+26=100. We can achieve it by removing the contestants of the districts 1, 3, and 4.

思路:删除点比较困难,可以保留点。很明显要尽量保留较大的点,因为2^n大于其余所有节点的值的和。那么以n为根节点建一棵树。

然后贪心保留n-1这个点,判断n-1这个点往根节点的第一个保留下来的节点之间路径的节点数是否小于或等于剩下的可以保留的节点数,若小于或等于,那么就把这条链上的点都保留下来,否则继续处理n-2这个点,以此类推。如果要以某个点为起点往上查找第一个被保留下来的点,就要利用树上的倍增了。

#include<bits/stdc++.h>
using namespace std;
const int MAX=1e6+10;
const int MOD=1e9+7;
const double PI=acos(-1.0);
typedef long long ll;
vector<int>e[MAX];
int nex[MAX][22],v[MAX];//v[i]判断i是否被保留下来
void dfs(int k,int fa)  //预处理nex数组
{
    for(int i=0;i<e[k].size();i++)
    {
        if(e[k][i]==fa)continue;
        nex[e[k][i]][0]=k;
        for(int j=1;j<=20;j++)nex[e[k][i]][j]=nex[nex[e[k][i]][j-1]][j-1];
        dfs(e[k][i],k);
    }
}
int check(int x,int tot)
{
    for(int i=20;i>=0;i--)
    {
        if(v[nex[x][i]]==0)
        {
            tot-=(1<<i);
            x=nex[x][i];
        }
    }
    return tot>=1;
}
int main()
{
    int n,k;
    cin>>n>>k;
    for(int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        e[x].push_back(y);
        e[y].push_back(x);
    }
    for(int i=0;i<=20;i++)nex[n][i]=n;
    dfs(n,n);
    v[n]=1;
    k=n-k-1;
    for(int i=n-1;i>=1;i--)//从大到小枚举要保留的点
    {
        if(check(i,k))
        {
            int next=i;
            while(v[next]==0)//把当前点到第一个被保留的点之间的点都保留下来
            {
                v[next]=1;
                next=nex[next][0];
                k--;
            }
        }
    }
    for(int i=1;i<=n;i++)if(v[i]==0)printf("%d ",i);
    return 0;
}




猜你喜欢

转载自blog.csdn.net/mitsuha_/article/details/80349281
今日推荐