D. Paths on the Tree

Problem - 1746D - Codeforces

思路:先分析一下题意,根据第一条性质,每次只能够从1开始,而第二条性质则表明对于每个节点来说,经过这个节点的子节点的路径条数应该尽量均衡,最大值与最小值相差不能超过1,所以我们考虑,如果当前要选择k个路径,而当前节点有cnt个子节点,那么每个子节点应该至少经过k/cnt个,同时有k%cnt个需要经过k/cnt+1个,那么我们发现这个问题可以递归的解决,那么我们可以考虑用树形dp,我们将fi0表示以i为根,并且经过ki个,fi1表示以i为根并且经过ki+1个,那么对于叶子节点来说,fi0=costi*k,fi1=costi*(k+1),而对于非叶子节点来说,因为所有的子节点都至少经过ki个,所有我们先将所有子节点的fj0求和为sum,令fi0=fi1=sum,那么我们还要再经过k%cnt个,那么我们就是挑几个子节点,然后让他变为fj1,那么我们可以将所有fj1-fj0排个序,按照降序排序,那么我们只需要将差值加上,就相当于这个变为了fj1,所以我们只需要求一下前k%cnt的和即可,这是对于fi0来说,而对于fi1来说,则还要多出来一次,那么我们只需要求和倒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;       
}          
相关推荐
倒头就睡的小比特2 天前
算法竞赛C++常用的STL
c++·算法
小羊没烦恼!2 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
猎头南楼2 天前
知识社区推荐系统实践:新用户冷启动与长短期兴趣建模的挑战 资深推荐算法工程师
人工智能·深度学习·算法·机器学习
旖旎夜光3 天前
力控面试题 01.01: 判定字符是否唯一(位运算) —— 题解
c++·学习·算法·leetcode·力控
wzdark3 天前
大规模并行计算中的负载均衡算法研究4
算法
Because_of_Her13 天前
并查集-听课笔记
笔记·算法·并查集
码流子3 天前
高速公路安全监测实践:碰撞监测预警+物联网底座,从感知到处置的闭环
大数据·人工智能·物联网·算法·架构
another heaven3 天前
【算法/C++ MD5算法能否逆解码?原理、C++实现与同类哈希算法对比】
c++·算法·哈希算法
wzdark3 天前
从算法设计模式看编程思维的抽象能力4
算法
2601_962218613 天前
万象生鲜系统称重自动多退少补算法解决生鲜非标品痛点
大数据·数据库·人工智能·python·算法