题面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 */