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