「CEOI2019」魔法树(DP+差分启发式合并)
生活随笔
收集整理的這篇文章主要介紹了
「CEOI2019」魔法树(DP+差分启发式合并)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
「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∈soni??dpk,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∈soni??dpk,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; }總結
以上是生活随笔為你收集整理的「CEOI2019」魔法树(DP+差分启发式合并)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [LOJ #521]「LibreOJ β
- 下一篇: P3295 [SCOI2016]萌萌哒(