数据范围:\(1<=N<=10^5,1<=W_i<=10^9\)ios
感受最近有点不在状态。。这题场上竟然没作出来也是服了c++
(代爷:“这不是普及组题吗?”,而后7minA掉了qwq)spa
从知足题意的分组的性质入手:code
(1)若是一条链是一组,那么这条链的两个端点的值必定分别对应最大值和最小值(不然把这个点从这条链里面去掉,而后并到另外一组里面并不会使答案变劣)blog
(2)若是一条链是一组,那么这条链的点权值随深度增长单调递增或递减(若是不单调的话,咱们能够从破坏单调性的地方断开变成多条链,并不会使答案变劣)ip
有了这两个性质以后dp就很显然了string
咱们对于每个点维护该点为链头的链中递增或递减时子树内的答案最大值,\(f[x][0]\)表示递增的答案,\(f[x][1]\)表示递减的答案,记\(sum=\sum\limits_{u\in son(x)}max(f[u][0],f[u][1])\),那么有:
\[ \begin{aligned} &(u\in son(x)\&\&w[u]>w[x])\\ &f[x][0]=max(sum-max(f[u][0],f[u][1])+f[u][0]+w[u]-w[x])\\ \\ &(u\in son(x)\&\&w[u]<w[x])\\ &f[x][1]=max(sum-max(f[u][0],f[u][1])+f[u][1]+w[x]-w[u]) \end{aligned} \]
最后\(ans=max(f[x][0],f[x][1],\sum\limits_{u\in son(1)}max(f[u][0],f[u][1]))\)it
mark:(弱智操做)dp的时候不要想固然地忽略掉路径上其余分叉的贡献。。io
mark:单调性单调性单调性qwqclass
#include<iostream> #include<cstdio> #include<cstring> #define ll long long using namespace std; const int N=1e5+10; struct xxx{ int y,nxt; }a[N*2]; int h[N],w[N]; ll f[N][2]; int n,m,tot; ll ans; void add(int x,int y){a[++tot].y=y; a[tot].nxt=h[x]; h[x]=tot;} void dfs(int x){ int u; ll sum=0; for (int i=h[x];i!=-1;i=a[i].nxt){ u=a[i].y; dfs(u); sum+=max(f[u][0],f[u][1]); } f[x][0]=f[x][1]=sum; for (int i=h[x];i!=-1;i=a[i].nxt){ u=a[i].y; if (w[x]<=w[u]) f[x][0]=max(f[x][0],sum-max(f[u][0],f[u][1])+f[u][0]+w[u]-w[x]); if (w[x]>=w[u]) f[x][1]=max(f[x][1],sum-max(f[u][0],f[u][1])+f[u][1]+w[x]-w[u]); } if (x==1){ ans=sum; ans=max(ans,max(f[x][0],f[x][1])); } } int main(){ #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); #endif int x,y; scanf("%d",&n); memset(h,-1,sizeof(h)); tot=0; for (int i=1;i<=n;++i) scanf("%d",w+i); for (int i=1;i<n;++i){ scanf("%d%d",&x,&y); add(x,y); } ans=0; dfs(1); printf("%lld\n",ans); }