codeforces 980e E. 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.

题意: 给你n 个点形成一颗无向树 ,然后每个节点的价值为2的i次方,现在要删除k个节点,使得留下来的节点是连通的并且价值最大。

思路: 我们要贪心的去留编号大的节点。 因为所有编号小的节点的价值加起来还不如编号大的节点价值大, 所以我们以n 节点为根节点,然后贪心从大到小,找编号到根节点的距离,如果距离小于等于res (当前的剩余节点个数) 那么我们就把路径上的全部标记就好了。 最最关键的就是查询的时候会TLE  ,所以要用倍增法 事先处理一下。

代码: 

#include<bits/stdc++.h>

using namespace std;

const int N =1e6+5;
vector< int >ve[N];
int n,k;
int vis[N];
int res;
int minn;
int fa[N];
int bfa[N][21];

void dfs(int u,int fat)
{
    fa[u]=fat;
    bfa[u][0]=fat;
    for(int i=1;i<=20;i++){
        bfa[u][i]=bfa[bfa[u][i-1]][i-1];
    }
    int sz=ve[u].size();
    for(int i=0;i<sz;i++){
        int v=ve[u][i];
        if(v==fat) continue;
        dfs(v,u);
    }
    return ;
}

int main()
{
    int u,v;
    scanf("%d %d",&n,&k);
    for(int i=1;i<n;i++)
    {
        scanf("%d %d",&u,&v);
        ve[u].push_back(v);
        ve[v].push_back(u);
    }

    res=n-k;
    dfs(n,n);
    vis[n]=1;

    /*for(int i=1;i<=n;i++)
    {
        printf("u : %d\n",u);
        for(int j=0;j<=20;j++) printf("%d ",bfa[i][j]);
        printf("\n");
    }
    */

    res--;

    for(int i=n-1;i>=1;i--)
    {
        if(vis[i]) continue;
        int len=1;
        int v=i;
        for(int j=20;j>=0;j--){
            if(!vis[bfa[v][j]]){
                v=bfa[v][j];
                //printf("j : %d fa %d\n",j,bfa[i][j]);
                len+=(1<<j);
            }
        }
        //printf("i : %d len : %d\n",i,len);

        if(len<=res){
            res-=len;
            int f=i;
            while(1)
            {
                if(vis[f]) break;
                vis[f]=1;
                f=fa[f];
            }
        }
    }

    for(int i=1;i<=n;i++) if(vis[i]==0) printf("%d ",i);

    return 0;
}

/*

15 3
9 11
11 8
7 9
9 14
12 8
10 7
1 14
1 5
12 15
10 3
5 2
13 15
4 13
6 4

*/

猜你喜欢

转载自blog.csdn.net/yjt9299/article/details/80292711