题意:
给你一棵树,每个点有点权。
现在最多可以走k次。
- 条件1:从1开始的路径。
- 条件2:且要满足,每个节点的儿子,覆盖率之差不能超过1.
思路:
1 tips
由题目的条件2出发。
考虑 1 号节点, 定义
e
[
1
]
.
s
i
z
e
(
)
e[1].size()
e[1].size()为1号节点的儿子数。
- 那么每个1号节点的儿子分到 k e [ 1 ] . s i z e ( ) \frac{k}{e[1].size()} e[1].size()k
- 最后还剩 k % e [ 1 ] . s i z e ( ) k\%e[1].size() k%e[1].size(),我们肯定分配给较大的。
解法
考虑dp
d
p
[
x
]
[
0
]
dp[x][0]
dp[x][0]表示 节点
x
x
x 分不到多的部分
d
p
[
x
]
[
1
]
dp[x][1]
dp[x][1]表示 节点
x
x
x 分得到多的部分
解法2:
因为我们发现,每次
d
f
s
(
x
,
k
)
dfs(x,k)
dfs(x,k)最多衍生出
d
f
s
(
v
,
k
e
[
x
]
.
s
i
z
e
(
)
)
,
v
∈
e
[
x
]
dfs(v,\frac{k}{e[x].size()}), v\in e[x]
dfs(v,e[x].size()k),v∈e[x] 和
d
f
s
(
v
,
k
e
[
x
]
.
s
i
z
e
(
)
+
1
)
,
v
∈
e
[
x
]
dfs(v,\frac{k}{e[x].size() } + 1), v\in e[x]
dfs(v,e[x].size()k+1),v∈e[x]
那么我们可以记忆化搜索。
AC 解法1
package com.hgs.codeforces.contest.globalround.contest23.d;
/**
* @author youtsuha
* @version 1.0
* Create by 2022/10/15 23:34
*/
import java.util.*;
import java.io.*;
public class Main {
static FastScanner cin;
static PrintWriter cout;
private static void init()throws IOException {
cin = new FastScanner(System.in);
cout = new PrintWriter(System.out);
}
private static void close(){
cout.close();
}
static int n, k;
static long s[];
static List<Integer> e[];
static long ans = 0;
static long dp[][];
static void dfs(int x, int k){
int time = 0;
int rem = 0;
long res = s[x]*k;
dp[x][1] = dp[x][0] = res;
dp[x][1] += s[x];
if(e[x].size() == 0){
return;
}
{
time = k/e[x].size();
rem = k%e[x].size();
}
List<Long> dif = new ArrayList<>();
for(int v: e[x]){
dfs(v, time);
dp[x][0] += dp[v][0];
dp[x][1] += dp[v][0];
dif.add(dp[v][1] - dp[v][0]);
}
Collections.sort(dif);
//0 1 2 3
int p = e[x].size() - rem;
for(int i = 0; i < dif.size(); i ++ ) {
if(i >= p) {
dp[x][0] += dif.get(i);
dp[x][1] += dif.get(i);
}
}
dp[x][1] += dif.get(p-1);
}
private static void sol()throws IOException {
n = cin.nextInt(); k =cin.nextInt();
e = new ArrayList[n];
for(int i = 0; i < n; i ++ ) e[i] = new ArrayList<>();
for(int i = 1; i < n; i ++ ) {
int p = cin.nextInt();
p--;
e[p].add(i);
}
s = new long[n];
for(int i = 0; i < n; i ++ ) s[i] = cin.nextLong();
dp = new long[n][2];
dfs(0,k);
cout.println(dp[0][0]);
}
public static void main(String[] args) throws IOException {
init();
int tt = cin.nextInt();
while(tt-- > 0)sol();
close();
}
}
class FastScanner {
BufferedReader br;
StringTokenizer st = new StringTokenizer("");
public FastScanner(InputStream s) {
br = new BufferedReader(new InputStreamReader(s));
}
public FastScanner(String s) throws FileNotFoundException {
br = new BufferedReader(new FileReader(new File(s)));
}
public String next() throws IOException {
while (!st.hasMoreTokens()){
try {
st = new StringTokenizer(br.readLine());
} catch (IOException e) { e.printStackTrace(); }
}
return st.nextToken();
}
public int nextInt() throws IOException {
return Integer.parseInt(next());
}
public long nextLong() throws IOException {
return Long.parseLong(next());
}
public double nextDouble() throws IOException {
return Double.parseDouble(next());
}
}