タイトル
n個のノードのルートツリーが与えられた場合、ルートはノード1です。
kノードを選択して工業都市として設定し、残りを観光都市として設定できます。
工業都市の場合、その幸せ値は、工業都市からルートまでのパスが通過する観光都市の数として定義されます。
あなたはすべての工業都市の幸福の価値の可能な最大の合計を求める必要があります。
\(1 <= k <= n <= 2 * 10 ^ 5 \) ;
解決策
考えてみれば、葉ノードからの奥行きが大きいセレクションであると考えるのも難しくないので
、順番に並べ替えて、奥行きに応じて大きいものから小さいものへと順に選択しますか???
しかし、これは本当ですか???
ポイントを工業都市の条件として注意深く考慮します:
まず、このポイントをルートとするサブツリーに選択されていないポイントがある場合、このポイントは間違いなく現在の最適な決定ではありません。
上記の項目を使用して、次のことを推定できます。
工業都市として選ばれるのは、その息子たちがすでに選ばれているという前提
次に、ポイントを工業都市として選択することの貢献を検討します。
- その深さ
- 産業都市として選択されたサブツリーのすべてのポイントを貢献させます-1
また、このポイントのサブツリーのすべてのポイントは工業都市である必要があるため、このポイントによってもたらされる値は次のとおりです:
\(値=その深さサブツリーサイズ\)
この\(値\)に従って、大きなルートヒープを維持し、各息子が選択されたポイントまたはそれ自体がリーフノードであるポイントを挿入する
コード
#include<bits/stdc++.h>
using namespace std;
#define re register
#define in inline
#define ll long long
#define get getchar()
in int read()
{
int t=0,x=1;char ch=get;
while((ch<'0'||ch>'9')&&ch!='-')ch=get;
if(ch=='-')x=-1,ch=get;
while(ch<='9'&&ch>='0')t=t*10+ch-'0',ch=get;
return x*t;
}
const int _=2e6+5;
struct edge{
int to,ne;
}e[_];
struct dian{
int id,deep;
}d[_];
int h[_],n,k,num[_],tot,father[_];
in void add(int x,int y)
{
e[++tot].to=y,e[tot].ne=h[x],h[x]=tot;
}
int val[_],siz[_],len[_];
in void dfs(int u,int fa)
{
d[u].id=u,d[u].deep=d[fa].deep+1;
siz[u]=1;father[u]=fa;
for(re int i=h[u];i;i=e[i].ne)
{
int v=e[i].to;
if(v==fa) continue;
dfs(v,u);
siz[u]+=siz[v];
}
}
in int cmp(dian a,dian b)
{
return a.deep>b.deep;
}
in ll work(int x)
{
return (d[x].deep-1)-siz[x]+1;
}
priority_queue<pair<ll,int> >q;
in void dfs2(int u,int fa)
{
len[u]+=len[fa];
if(!val[u]) len[u]++;
for(re int i=h[u];i;i=e[i].ne)
{
int v=e[i].to;
if(v==fa) continue;
dfs2(v,u);
}
}
int main()
{
n=read(),k=read();
for(re int i=1;i<n;i++)
{
int x=read(),y=read();
add(x,y),add(y,x);
num[x]++,num[y]++; //统计每个点的度数,之后要统计哪些点成为"叶子"节点
}
dfs(1,0); //求深度、子树大小、父亲节点编号
for(re int i=1;i<=n;i++)
if(num[i]==1)
q.push(make_pair(work(i),i)); //把真正的叶子加入优先队列
while(k--)
{
int u=q.top().second;q.pop();
val[u]=1;num[father[u]]--; //val[i]为1 表示此点已是工业城市;将父亲节点的度数-1
if(1==num[father[u]]) //若父亲节点度数为1,则说明父亲节点的所有儿子都已经成为了工业城市,所以该父亲节点也有了“候选资格”
q.push(make_pair(work(father[u]),father[u]));
}
dfs2(1,0); //统计每个工业城市的答案
ll ans=0;
for(re int i=1;i<=n;i++)
if(val[i])
ans+=len[i];
cout<<ans<<endl;
return 0;
}