題面c++
題意:自已去看git
題解:首先考慮dp。設\(dp_{i,j}\)表示\(i\)的子樹內,總時間爲\(j\)時的最大收益。轉移是顯然的,能對其形成貢獻的是每個兒子\(v\)的\(dp_{v,k}(k \leq j)\)。而後再加上本身的貢獻便可。數組
優化1:發現有用的時間只有\(n\)種,因此能夠將時間離散化。時間複雜度是\(O(n^2)\)的。優化
優化2:咱們先不考慮當前節點的貢獻。發現兩個兒子直接合並的複雜度是\(O(n)\)的,考慮優化。發現對於每一個\(i\)和其子樹內出現過的\(j\),\(dp_{i,j}\)必定是遞增的,由於\(dp_{i,j}=max(dp_{i,j},dp_{i,j-1})\)。因此若是咱們用map記錄\(dp\)數組,並將\(dp\)數組差分,那麼就能作到啓發式合併了。直接合並兩個map便可。spa
最後考慮當前節點的果實的貢獻。設當前節點果實成熟的時間爲\(t\),那麼\(dp_{i,t}+=w_i\),而後考慮有一些\(dp_{i,j}(j>t)\)會比\(dp_i,t\)小,那麼找到這些小的,把它們從map裏刪除就好了。code
時間複雜度:\(O(nlog^2n)\)。get
代碼:it
#include<bits/stdc++.h> using namespace std; #define re register int #define F(x,y,z) for(re x=y;x<=z;x++) #define FOR(x,y,z) for(re x=y;x>=z;x--) typedef long long ll; #define I inline void #define IN inline int #define C(x,y) memset(x,y,sizeof(x)) #define STS system("pause") template<class D>I read(D &res){ res=0;register D g=1;register char ch=getchar(); while(!isdigit(ch)){ if(ch=='-')g=-1; ch=getchar(); } while(isdigit(ch)){ res=(res<<3)+(res<<1)+(ch^48); ch=getchar(); } res*=g; } vector<int>e[101000],vec[101000]; map<int,ll>s[101000]; int n,m,k,fa[101000],root[101000],t[101000]; ll w[101000]; ll ans,sum; inline bool bbb(int x,int y){return t[x]==t[y]?w[x]<w[y]:t[x]<t[y];} I D_1(int x){ for(auto d:e[x]){ D_1(d); if(s[x].size()<s[d].size())swap(s[x],s[d]); for(auto it=s[d].begin();it!=s[d].end();it++){ s[x][it->first]+=it->second; } s[d].clear(); } sort(vec[x].begin(),vec[x].end(),bbb); for(auto d:vec[x]){ s[x][t[d]]+=w[d];register ll dt=w[d]; for(auto it=s[x].upper_bound(t[d]),tmp=it;it!=s[x].end();){ if(dt>=it->second){dt-=it->second;tmp=it++,s[x].erase(tmp);} else{it->second-=dt;break;} } } } int main(){ read(n);read(m);read(k); F(i,2,n)read(fa[i]),e[fa[i]].emplace_back(i); re X; F(i,1,m){ read(X);vec[X].emplace_back(i); read(t[i]);read(w[i]); } D_1(1); for(auto it=s[1].begin();it!=s[1].end();it++){ sum+=it->second; } printf("%lld",sum); return 0; } /* 6 4 10 1 2 1 4 4 3 4 5 4 7 2 5 4 1 6 9 3 */