题目链接:http://codeforces.com/contest/1059/problem/E
题目大意:给出一棵有 n 个结点的树,每个结点都有一个权值 w ,现在要你将这棵树分成若干条链,且每个结点只能属于一条链,分出来的链满足每条链上的结点不超过L个,同时这些结点的权值和不超过S。问你最少能把这棵树分成几条链。
题目思路:由于是要使得链尽可能的少,所以分出来的链每条链上的结点都是要尽可能的多的。
但如果从上往下去将树分链的话操作起来会很麻烦,所以我们可以考虑至下往上去分链。
由于叶子结点之间是不会有交集的,所以每个叶子结点必然会分出一条链来。然后我们就可以考虑至下往上贪心的做法,由于要使得链上结点尽可能的多,所以我们可以通过树上倍增的做法,预处理出每个结点从下往上形成的链最远能到哪里。
预处理出这个信息之后,我们就可以对答案进行求解了,每次就取不属于已取出链的一个结点,将其能形成的最长链变成一条新的链即可。
具体实现看代码:
#include <bits/stdc++.h>
#define fi first
#define se second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pb push_back
#define MP make_pair
#define lowbit(x) x&-x
#define clr(a) memset(a,0,sizeof(a))
#define _INF(a) memset(a,0x3f,sizeof(a))
#define FIN freopen("in.txt","r",stdin)
#define IOS ios::sync_with_stdio(false)
#define fuck(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
typedef pair<ll, ll>pll;
const int MX = 1e5 + 5;
const double eps = 1e-8;
int n, L, ans;
ll S, dis[MX];
vector<int>G[MX];
int val[MX], ST[MX][20], dep[MX], top[MX], head[MX];
//ST为倍增数组;dis数组表示从上往下的权值前缀和,这样求一条链的权值和只要减一下即可;
//dep为结点的深度;top表示该结点所能到达的最远结点;head表示分出来的链最上端的结点;
void ST_init() {
for (int i = 1; i < 20; i++) {
for (int j = 1; j <= n; j++)
ST[j][i] = ST[ST[j][i - 1]][i - 1];
}
}
void dfs1(int u, int fa) {
dis[u] = dis[fa] + val[u];
dep[u] = dep[fa] + 1;
top[u] = u;
int cnt = L;
for (int i = 19; i >= 0; i--) {
int f = ST[top[u]][i];
if ((1 << i) >= cnt || f == 0) continue;
if (dis[u] - dis[ST[f][0]] > S) continue;
cnt -= (1 << i);
top[u] = f;
}
for (auto v : G[u]) dfs1(v, u);
}
void dfs2(int u) {
int res = -1;
for (auto v : G[u]) {
dfs2(v);
if (head[v] == v) continue;
if (res == -1 || dep[res] > dep[head[v]]) res = head[v];
}
if (res == -1) {
res = top[u];
ans++;
}
head[u] = res;
}
int main() {
// FIN;
scanf("%d%d%lld", &n, &L, &S);
bool flag = 0;
for (int i = 1; i <= n; i++) {
scanf("%d", &val[i]);
if (val[i] > S) flag = 1;
}
if (flag) {
puts("-1");
return 0;
}
for (int i = 2, p; i <= n; i++) {
scanf("%d", &p);
G[p].pb(i);
ST[i][0] = p;
}
ST_init();
dfs1(1, 0); dfs2(1);
cout << ans << endl;
return 0;
}