「CEOI2019」魔法树
description
solution
设dpi,j:idp_{i,j}:idpi,j:i子树在jjj时刻的最大果汁量,显然dpi,jdp_{i,j}dpi,j在jjj是单调递增的 dpi,j=max(dpi,j,dpi,j−1)dp_{i,j}=\max(dp_{i,j},dp_{i,j-1})dpi,j=max(dpi,j,dpi,j−1)
-
iii不收获
dpi,j=∑k∈sonidpk,jdp_{i,j}=\sum_{k∈son_i}dp_{k,j}dpi,j=∑k∈sonidpk,j
-
iii在jjj时刻收获,要保证j≥dij\ge d_ij≥di
dpi,j=wi+∑k∈sonidpk,didp_{i,j}=w_i+\sum_{k∈son_i}dp_{k,d_i}dpi,j=wi+∑k∈sonidpk,di
只有nnn个时刻,可以离散化,暴力转移是O(n2)O(n^2)O(n2)
可以考虑差分map
进行启发式合并
在iii成熟的ttt时刻时,进行dpi,t+=widp_{i,t}+=w_idpi,t+=wi
此时会出现j>tj>tj>t但是dpi,j<dpi,tdp_{i,j}<dp_{i,t}dpi,j<dpi,t的情况,直接删除即可
code
#include <map>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
#define int long long
#define maxn 100005
map < int, int > dp[maxn];
vector < int > G[maxn], fruit[maxn];
int n, m, k;
int d[maxn], w[maxn];bool cmp( int x, int y ) {return d[x] == d[y] ? w[x] < w[y] : d[x] < d[y];
}void dfs( int now ) {for( int son : G[now] ) {dfs( son );if( dp[now].size() < dp[son].size() )swap( dp[now], dp[son] );for( auto i = dp[son].begin();i != dp[son].end();i ++ )dp[now][i -> first] += i -> second;dp[son].clear();}sort( fruit[now].begin(), fruit[now].begin(), cmp );for( int son : fruit[now] ) {dp[now][d[son]] += w[son]; int r = w[son];for( auto i = dp[now].upper_bound( d[son] ), t = i;i != dp[now].end(); ) {if( r >= i -> second ) {r -= i -> second;t = i ++;dp[now].erase( t );}else {i -> second -= r;break;}}}
}signed main() {scanf( "%lld %lld %lld", &n, &m, &k );for( int i = 2, fa;i <= n;i ++ ) {scanf( "%lld", &fa );G[fa].push_back( i );}for( int i = 1, v;i <= m;i ++ ) {scanf( "%lld %lld %lld", &v, &d[i], &w[i] );fruit[v].push_back( i );}dfs( 1 );int ans = 0;for( auto i = dp[1].begin();i != dp[1].end();i ++ )ans += i -> second;printf( "%lld\n", ans );return 0;
}