動態規劃專項訓練記錄 2024.3

wangsiqi2010916發表於2024-03-16

Paths on the Tree

若使分數最大,則儘量每條路徑都到葉子,看到題目說絕對值差不超過1,可以發現是要儘量平均分配,設餘r條路徑

既然要最大化貢獻且剩下的路徑要不重複的分配,那就選取前r條從該節點到葉子節點權值和最大的鏈,遞迴求取

但有一種情況,若在點u選了路徑t,在fa再次選擇,就會不滿足,所以向上返回時應返回第r+1大的路徑

程式碼:

#include<cstdio>
#include<cstring>
#include<queue>
#define ll long long
using namespace std;
int n,T,k,head[200005],edgenum;
ll a[200005];
struct edge{
	int to,nxt;
}e[400005];
void add_edge(int u,int v)
{
	e[++edgenum].nxt=head[u];
	e[edgenum].to=v;
	head[u]=edgenum;
}
ll ans;
void init()
{
	edgenum=ans=0;
	memset(head,0,sizeof(head));
}
int son[200005];
void dfs(int u,int fa)
{
	son[u]=0;
	for(int i=head[u];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==fa) continue;
		dfs(v,u);
		son[u]++;
	}
}
ll dfs2(int u,int k,int fa)
{
	ans+=1ll*k*a[u];
	if(!son[u]) return a[u];
	int t=k/son[u],r=k%son[u];
	priority_queue<ll>q;
	while(!q.empty()) q.pop();
	for(int i=head[u];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==fa) continue;
		q.push(dfs2(v,t,u));
	}
	while(r--)
	{
		ans+=q.top();
		q.pop();
	}
	return q.top()+a[u];
}
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&k);
		init();
		for(int i=2;i<=n;i++)
		{
			int fa;
			scanf("%d",&fa);
			add_edge(i,fa);
			add_edge(fa,i);
		}
		for(int i=1;i<=n;i++)
		{
			scanf("%lld",&a[i]);
		}
		dfs(1,0);
		//printf("1");
		int tmp=dfs2(1,k,0);
		printf("%lld\n",ans);
	}
	return 0;
}

相關文章