CF1336 Linova and Kingdom

Title

Given a rooted tree of n nodes, the root is node 1.

You can choose k nodes to set it as an industrial city, and the rest as tourist cities.

For an industrial city, its happiness value is defined as the number of tourist cities through which the path from industrial city to root passes.

You need to ask for the maximum possible sum of the happiness values ​​of all industrial cities.

\(1<=k<=n<=2*10^5\);

Portal

answer

If you think about it, it is not difficult to think that it must be a selection with a large depth from the leaf node .
Then the method is to sort through the order, and then select from the largest to the smallest according to the depth ? ? ?

But is this really the case? ? ?

We carefully consider a point as the conditions and conditions of the industrial city:

First, if there is a point in the subtree rooted at this point that is not selected, then this point is definitely not the current optimal decision.
With the above item, we can deduce:

The premise of being selected as an industrial city is that its sons have already been selected

Then let us consider the contribution of choosing a point as an industrial city:

  • Its depth
  • It will make every point in its subtree that has been selected as an industrial city contribute -1

And because every point in the subtree of this point must be an industrial city , the value contributed by this point is:
\ (value = its depth-subtree size \)

According to this \ (value \) maintain a large root heap, just insert the point where each son has been selected or is itself a leaf node

Code

#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;
}

Guess you like

Origin www.cnblogs.com/yzhx/p/12723121.html