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;       
}          
相关推荐
wabs66611 分钟前
关于贪心算法【划分字母区间】的问题总结(C++语法)
算法·贪心算法
啦啦啦啦啦zzzz41 分钟前
数据结构:二叉树的线索化
数据结构·算法
2401_872418781 小时前
算法入门:并查集(Disjoint Set / Union-Find):连通性问题的利器
算法
luj_17681 小时前
R语言生态优势与学习曲线分析
c语言·开发语言·网络·经验分享·算法
计算机安禾1 小时前
【算法分析与设计】第36篇:计算几何基础:凸包问题的分治与扫描线解法
大数据·人工智能·算法·机器学习·剪枝
货拉拉技术1 小时前
飞速发展的计算机视觉
人工智能·算法
如竟没有火炬2 小时前
寻找峰值——二分
java·开发语言·数据结构·python·算法·散列表
noipp2 小时前
推荐题目:洛谷 P1115 最大子段和
算法
Lumbrologist2 小时前
【C++】零基础入门 · 第 17 节:多线程编程基础
java·c++·算法
轻闲一号机2 小时前
【语音】笔记
前端·笔记·算法