ライトノベルを書くことは、リノバの人生で最も重要なことです。昨夜、Linovaは幻想的な王国を夢見ていた。彼女は目覚めるとすぐに王国のためにライトノベルを書き始めました、そしてもちろん、彼女はそれの女王です。
王国にはnつの都市と2つの都市を結ぶn-1の双方向道路があります。どの都市からでも、いくつかの道路を歩いて他の都市に行くことができます。都市には1からnまでの番号が付けられており、都市1は王国の首都です。それで、王国は木構造を持っています。
女王として、Linovaは正確にk都市を開発する産業を選択することを計画し、他の都市は観光を開発します。首都は、工業都市または観光都市のいずれかです。
年に一度、首都で会議が開かれます。会議に出席するために、各産業都市は特使を送ります。すべての特使は出発都市から首都への最短経路をたどります(これはユニークです)。
観光都市での旅行は楽しいです。使節ごとに、彼の幸せは彼の道にある観光都市の数に等しい。
人々に愛される女王になるために、Linovaはすべての使節の幸福の合計を最大化できるkの都市を選択したいと考えています。彼女の最大合計を計算できますか?
入力
最初の行には、2つの整数nとk(2≤n≤2⋅105、1≤k<n)が含まれています。それぞれ都市と産業都市の数です。
次のn-1行のそれぞれに2つの整数uとv(1≤u、v≤n)が含まれ、都市uと都市vを結ぶ道路があることを示しています。
どの都市からでも、道路で他のどの都市にもアクセスできることが保証されています。
出力
単一の整数(すべての特使の幸福の可能な最大の合計)を含む唯一の行を出力します。
例
入力
7 4
1 2
1 3
1 4
3 5
3 6
4 7
出力
7
入力
4 1
1 2
1 3
2 4
出力
2
入力
8 5
7 5
1 7
6 1
3 7
8 3
2 1
4 5
出力
9
注
最初の例では、Linovaは都市2、5、6、7を選択して産業を発展させることができます。次に、都市2の特使の幸福は1、都市5、6、7の使節の幸福は2です。幸福の合計7はであり、最大の一つであることが証明できる。
でザ・第二の例では、都市を選ぶ。3 ,. 4の産業CAN REACH A SUMを開発する。3、しかし、産業、そして最大SUMを開発し、正確に選択してKの都市にそのLinova計画を忘れないでください
アイデアは2です。この質問の鍵は、数値ポイントを選択するときにどのように決定するかです。つまり、このポイントによってもたらされる貢献とこのポイントによってもたらされる損失との差が最大になるはずです。図に示すように、
4の場合:これを選択した場合、その寄与はその深さ[4]であり、それがもたらす損失は、その2つの息子ノードの都市数が少ないことです。息子が少ない[4]。それは2です。
9の場合:それを選択すると、それがもたらす貢献はその深さ[9]であり、それがもたらす損失は、その2つの息子ノードが行く都市が少ないことです。息子が少ない[9]、つまり3です。
(、どうですか?私たちの貪欲と思うが、それを持って来る確かに最初の大深度ポイントをより良い番号を選択し、そう、あなたはこの点を選択した場合、それは彼の息子のノードを選択する必要がありますなぜ損失は息子の数である。)
私たちは、比較します違いを見ると、9の方が良いことがわかります。
つまり、deep [i] -son [i]> deep [j] -son [j]です。選択が最適であることを保証するために、この前提を保証する必要があります。したがって、dfsを1回実行し、深度と息子ノードの数を処理してから、並べ替えます。
コードは次のとおりです。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxx=2e5+100;
struct edge{
int to,next;
}e[maxx<<1];
struct node{
ll son;
ll dep;
int id;
bool operator<(const node &a)const{
return dep-son>a.dep-a.son;
}
}p[maxx];
int head[maxx<<1],vis[maxx];
ll deep[maxx],son[maxx];
int n,tot,k;
inline void init()
{
memset(head,-1,sizeof(head));
memset(vis,0,sizeof(vis));
tot=0;
for(int i=1;i<=n;i++) p[i].dep=p[i].son=0;
}
inline void add(int u,int v)
{
e[tot].next=head[u],e[tot].to=v,head[u]=tot++;
}
inline void dfs(int u,int f,int num)
{
p[u].dep=num;
p[u].son=1;
p[u].id=u;
for(int i=head[u];i!=-1;i=e[i].next)
{
int to=e[i].to;
if(to==f) continue;
dfs(to,u,num+1);
p[u].son+=p[to].son;
}
}
inline void Dfs(int u,int f,ll &ans)
{
if(k<=0) return ;
if(vis[u]==1)
{
ans+=(ll)min((ll)k,son[u])*(ll)deep[u];
k-=son[u];
return ;
}
for(int i=head[u];i!=-1;i=e[i].next)
{
int to=e[i].to;
if(to==f) continue;
Dfs(to,u,ans);
}
}
int main()
{
scanf("%d%d",&n,&k);
init();
int x,y;
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
dfs(1,0,0);
sort(p+1,p+1+n);
for(int i=1;i<=k;i++) vis[p[i].id]=1;
for(int i=1;i<=n;i++) deep[p[i].id]=p[i].dep,son[p[i].id]=p[i].son;
ll ans=0;
Dfs(1,0,ans);
cout<<ans<<endl;
return 0;
}
頑張って(o)/〜