東非大裂谷

Description

  數據範圍:\(1<=N<=10^5,1<=W_i<=10^9\)ios

  

Solution

  感受最近有點不在狀態。。這題場上竟然沒作出來也是服了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

  

Code

#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);
}
相關文章
相關標籤/搜索