codeforces980e(倍增、贪心|| 树的dfs序差分+树状数组)

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 (1≤k<n≤1061≤k<n≤106) — the number of districts in Panel, and the number of contestants the president wishes to remove, respectively.

The next n−1n−1 lines each contains two integers aa and bb (1≤a,b≤n1≤a,b≤n, a≠ba≠b), that describe a road that connects two different districts aa and 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个点形成一棵树,序号1~n,每个点的value为2^i,现在要去掉k个点,使得其余的点还是一棵树并且值和最大,求去掉哪些点。

思路:

1、采用topo不能够得到正确答案。我们肯定是要贪心来做,保大。n必须留下作为根节点,再遍历n-1~1这几个节点,如果满足要求则把这个节点及其到根节点的枝都留下,如果不满足要求(要留下的超过了数目)则不留。在遍历一个节点的祖先节点的时候采用倍增预处理。

#include <bits/stdc++.h>  
using namespace std;  
const int maxn = 1e6 + 100;  
vector<int>tr[maxn];  
int par[maxn];  
int up[22][maxn];  
bool used[maxn];  
void dfs(int u, int fa)  
{  
    par[u] = up[0][u] = fa;  
    for(int i = 1;i<22;i++) 
        up[i][u] = up[i-1][up[i-1][u]];  
    for(int to=0;to<tr[u].size();to++) 
        if(tr[u][to]!=fa) 
            dfs(tr[u][to],u);  
}  
  
int main()  
{  
    int n, k;  
    scanf("%d %d", &n, &k);  
    for(int i=0;i<=n;i++)
        tr[i].clear();
    memset(used,0,sizeof(used));
    int u,v;
    for(int i = 1;i < n;i ++) {  
        scanf("%d %d",&u,&v);  
        tr[u].push_back(v);  
        tr[v].push_back(u);  
    }  
    dfs(n, n);  
    int all = n - k - 1;
    used[n] = 1; 
    for(int i = n-1;i;i--)
    {
        if(used[i])continue;
        int v = i,len = 1;
        for(int j = 21;j>=0;j--)
        {
            if(!used[up[j][v]])
            {
                len += (1<<j);
                v = up[j][v];
            }
        }
        if(len<=all)
        {
            all -= len;
            v = i;
            while(!used[v])
            {
                used[v] = 1;
                v = par[v];
            }
        }
    } 
    for(int i = 1;i <= n; i++) 
        if(!used[i]) printf("%d%c",i,i==n?'\n':' ');   
    return 0;  
} 

还有一种方法:利用树的dfs序(还是以n为根),可以确定一个节点的子树(前序遍历后序遍历确定),然后通过差分,增加一个节点就在这个节点子树开始位置+1,在子树结束后位置-1,这样对别的子树影响不到。通过树状数组查询可以确定这个节点的祖先节点有几个不用remove。过程还是贪心地取。

代码:http://codeforces.com/contest/980/submission/50068081

树状数组(Fenwick Tree)是一种用于高效处理区间和查询的数据结构,常用于解一维数组的前缀和、区间更新和查询等问题。 在 Codeforces 上,树状数组常被用来解决一些与区间和查询有关的问题。它可以在 O(logn) 的时间内完成单点更新和查询,以及区间求和等操作。 下面是一个简单的示例代码,展示了如何实现一个基本的树状数组: ```cpp #include <iostream> #include <vector> using namespace std; // 获取最低位的 1 int getLowbit(int x) { return x & -x; } // 树状数组的单点更新操作 void update(vector<int>& fenwick, int index, int delta) { while (index < fenwick.size()) { fenwick[index] += delta; index += getLowbit(index); } } // 树状数组的前缀和查询操作 int query(vector<int>& fenwick, int index) { int sum = 0; while (index > 0) { sum += fenwick[index]; index -= getLowbit(index); } return sum; } int main() { int n; cin >> n; vector<int> fenwick(n + 1, 0); // 初始化树状数组 for (int i = 1; i <= n; i++) { int val; cin >> val; update(fenwick, i, val); } // 进行查询操作 int q; cin >> q; while (q--) { int type; cin >> type; if (type == 1) { int index, delta; cin >> index >> delta; update(fenwick, index, delta); } else if (type == 2) { int l, r; cin >> l >> r; int sum = query(fenwick, r) - query(fenwick, l - 1); cout << sum << endl; } } return 0; } ``` 在这个示例中,我们使用了一个长度为 n 的数组 `fenwick` 来表示树状数组。`update` 函数用于更新树状数组中的某个元素,`query` 函数用于查询树状数组中某个区间的和。 你可以根据具体问题的要求进行相应的修改和扩展。希望对你有所帮助!如果有任何疑问,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值