【题解】CF1336A Linova and Kingdom
分析 + 题解
看到一道跟树相关的题目,你想到了什么?树形 DP?dfs 序?还是树剖?
我相信,当你读完题面和样例解释后,你一定会说:“都不是,这只是个贪心罢了。”
没错,一种显然的贪心策略是(从下往上)选择深度尽量大、子树大小尽量小的节点,但这不完全正确,因为你没有求得这两个属性在最优性中的权重,下面将进行推导。
首先给出一个显然正确的结论:将一个节点作为工业城市的必要不充分条件是,这个节点所在子树的其他节点均已作为工业城市。
证明:若存在一个工业城市
这启发我们一件事:点
说明:此时,
因此,我们只需贪心选取
有人可能会问,需不需要考虑上文提到的必要条件。答案是否定的,因为对于任意父子关系
代码实现
只需遍历一遍树,计算出 nth_element() 求得
时间复杂度:
轻轻松松最优解^_^
补充:有关 STL 中的 nth_element()
作用:求区间第
用法:前三个参数分别为起始位置,第
时间复杂度:
代码
#include<bits/stdc++.h>
using namespace std;
const int max_n=2e5+5;
int End[max_n<<1],Last[max_n],Next[max_n<<1],e;
inline void add_edge(int x,int y)
{
End[++e]=y;
Next[e]=Last[x];
Last[x]=e;
End[++e]=x;
Next[e]=Last[y];
Last[y]=e;
}
int dep[max_n],sz[max_n],val[max_n];
void dfs(int x,int fa)
{
dep[x]=dep[fa]+1;
sz[x]=1;
for(int i=Last[x];i;i=Next[i])
{
int y=End[i];
if(y!=fa)
{
dfs(y,x);
sz[x]+=sz[y];
}
}
val[x]=dep[x]-sz[x];
}
int main()
{
int n,k;
scanf("%d%d",&n,&k);
for(int i=1;i<=n-1;++i)
{
int u,v;
scanf("%d%d",&u,&v);
add_edge(u,v);
}
dfs(1,0);
nth_element(val+1,val+k,val+n+1,greater<int>());//看似求第 k 大,实则获得前 k 大
long long ans=0;
for(int i=1;i<=k;++i)
ans+=val[i];
printf("%lld\n",ans);
return 0;
}