D. Paths on the Tree

Problem - 1746D - Codeforces

思路:先分析一下题意,根据第一条性质,每次只能够从1开始,而第二条性质则表明对于每个节点来说,经过这个节点的子节点的路径条数应该尽量均衡,最大值与最小值相差不能超过1,所以我们考虑,如果当前要选择k个路径,而当前节点有cnt个子节点,那么每个子节点应该至少经过k/cnt个,同时有k%cnt个需要经过k/cnt+1个,那么我们发现这个问题可以递归的解决,那么我们可以考虑用树形dp,我们将f[i][0]表示以i为根,并且经过ki个,f[i][1]表示以i为根并且经过ki+1个,那么对于叶子节点来说,f[i][0]=cost[i]*k,f[i][1]=cost[i]*(k+1),而对于非叶子节点来说,因为所有的子节点都至少经过ki个,所有我们先将所有子节点的f[j][0]求和为sum,令f[i][0]=f[i][1]=sum,那么我们还要再经过k%cnt个,那么我们就是挑几个子节点,然后让他变为f[j][1],那么我们可以将所有f[j][1]-f[j][0]排个序,按照降序排序,那么我们只需要将差值加上,就相当于这个变为了f[j][1],所以我们只需要求一下前k%cnt的和即可,这是对于f[i][0]来说,而对于f[i][1]来说,则还要多出来一次,那么我们只需要求和倒k%cnt+1即可,并且k%cnt+1按照相同的方法取最大的k%cnt+1个一定也是正确的,因为k%cnt最大为cnt-1个,加一为cnt个,正好等于子节点的个数,所以一定是合法的取法

cpp 复制代码
// Problem: D. Paths on the Tree
// Contest: Codeforces - Codeforces Global Round 23
// URL: https://codeforces.com/problemset/problem/1746/D
// Memory Limit: 256 MB
// Time Limit: 3000 m

#include<bits/stdc++.h>
#include<sstream>
#include<cassert>
#define fi first
#define se second
#define i128 __int128
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> PII;
const double eps=1e-7;
const int N=5e5+7 ,M=5e5+7, INF=0x3f3f3f3f,mod=1e9+7,mod1=998244353;
const long long int llINF=0x3f3f3f3f3f3f3f3f;
inline ll read() {ll x=0,f=1;char c=getchar();while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') {x=(ll)x*10+c-'0';c=getchar();} return x*f;}
inline void write(ll x) {if(x < 0) {putchar('-'); x = -x;}if(x >= 10) write(x / 10);putchar(x % 10 + '0');}
inline void write(ll x,char ch) {write(x);putchar(ch);}
void stin() {freopen("in_put.txt","r",stdin);freopen("my_out_put.txt","w",stdout);}
bool cmp0(int a,int b) {return a>b;}
template<typename T> T gcd(T a,T b) {return b==0?a:gcd(b,a%b);}
template<typename T> T lcm(T a,T b) {return a*b/gcd(a,b);}
void hack() {printf("\n----------------------------------\n");}

int T,hackT;
int n,m,k;
int h[N],e[M],ne[M],idx;
ll f[N][2];
int cost[N];

void add(int a,int b) {
	e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void dfs(int u,int k) {
	f[u][0]=(ll)cost[u]*k;
	f[u][1]=(ll)cost[u]*(k+1);
	int cnt=0;
	for(int i=h[u];i!=-1;i=ne[i]) {
		int j=e[i];
		cnt++;
	}
	if(!cnt) return ;
	int a=k/cnt,b=k%cnt;
	
	vector<ll> vis;
	for(int i=h[u];i!=-1;i=ne[i]) {
		int j=e[i];
		dfs(j,a);
		f[u][0]+=f[j][0];
		f[u][1]+=f[j][0];
		vis.push_back(f[j][1]-f[j][0]);
	}
	
	sort(vis.begin(),vis.end(),[&](ll &a,ll &b){
		return a>b;
	});
	
	for(int i=0;i<b;i++) f[u][0]+=vis[i];
	for(int i=0;i<=b;i++) f[u][1]+=vis[i];
}

void solve() {
	n=read(),k=read();
	
	memset(h,-1,sizeof(int)*(n+4));
	idx=0;
	
	for(int i=2;i<=n;i++) {
		int c=read();
		add(c,i);
	}
	
	for(int i=1;i<=n;i++) cost[i]=read();
	
	dfs(1,k);
	
	printf("%lld\n",f[1][0]);
}   

int main() {
    // init();
    // stin();
	// ios::sync_with_stdio(false); 

    scanf("%d",&T);
    // T=1; 
    while(T--) hackT++,solve();
    
    return 0;       
}          
相关推荐
菜喵一只7 分钟前
计算2的N次方
数据结构·算法
C咖咖20 分钟前
github算法
算法·algorithm
凡人的AI工具箱44 分钟前
15分钟学 Go 第 54 天 :项目总结与经验分享
开发语言·人工智能·后端·算法·golang
OKkankan1 小时前
单链表算法题(数据结构)
c语言·数据结构·数据库·c++·算法
ZZZ_O^O1 小时前
动态规划-背包问题——[模版]完全背包问题
c++·学习·算法·leetcode·动态规划
Koishi_TvT1 小时前
蓝桥杯c++算法学习【3】之思维与贪心(重复字符串、翻硬币、乘积最大、皮亚诺曲线距离【难】:::非常典型的必刷例题!!!)
c++·学习·算法·游戏·贪心算法·蓝桥杯·c
t5y222 小时前
【C语言】Union
c语言·开发语言·算法
MATLAB滤波2 小时前
二维、三维情况下的锚点优选方法
算法·matlab·定位
ZZZ_O^O2 小时前
动态规划-背包问题——1049.最后一块石头的重量II
c++·学习·算法·leetcode·动态规划
xisai883 小时前
2025年开考科目有哪些?
java·开发语言·javascript·算法·kotlin