JZOJ5874. 【NOIP2018提高組模擬9.18】小p的決心
阿新 • • 發佈:2018-12-11
題解
考慮哪一些點可以變為相鄰的兒子節點, 就是某個點以及它的右鏈,和這個點父親的下一個兒子以及它的左鏈,這裡面的點都可兩兩相互成為相鄰的葉子節點。 於是就開始dp, 設表示最後一個葉子節點在i的時候是最大值, 考慮如何轉移, 很顯然,先找出兩條鏈來,這個過程類似求lca的過程。 然後維護一個字首, 討論新構成的鏈的最大值在哪一條鏈上面。
code
#include <iostream> #include <algorithm> #include <cstring> #include<cstdio> #include <string.h> #include <cmath> #include <math.h> #define ll long long #define N 1000003 #define P putchar #define G getchar using namespace std; char ch; void read(int &n) { n=0; ch=G(); while((ch<'0' || ch>'9') && ch!='-')ch=G(); ll w=1; if(ch=='-')w=-1,ch=G(); while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G(); n*=w; } int max(int a,int b){return a>b?a:b;} int min(int a,int b){return a<b?a:b;} ll abs(ll x){return x<0?-x:x;} ll sqr(ll x){return x*x;} void write(ll x){if(x>9) write(x/10);P(x%10+'0');} int lst[N],nxt[N],to[N],tot; int son[N],v[N],f[N],g[N],fa[N],id,n,m; int now,dfn[N],dep[N],ans,q[N],x,y,mx[N]; int d1[N],d2[N],t1,t2; void ins(int x,int y) { fa[y]=x; nxt[++tot]=lst[x]; to[tot]=y; lst[x]=tot; } void dfs(int x) { dfn[++now]=x;dep[x]=dep[fa[x]]+1; for(int i=lst[x];i;i=nxt[i]) dfs(to[i]),son[x]=1; if(!son[x])q[++q[0]]=x; } int main() { freopen("temmie.in","r",stdin); freopen("temmie.out","w",stdout); read(n); for(int i=1;i<=n;i++) { read(v[i]);read(m); for(int j=1;j<=m;j++)read(x),ins(i,x); } memset(son,0,sizeof(son)); dfs(1); for(x=q[1];x;x=fa[x])f[x]=v[x]; for(int i=2;i<=q[0];i++) { t1=t2=0; for(x=q[i-1],y=q[i];dep[x]>dep[y];x=fa[x])d1[++t1]=x; for(;dep[x]<dep[y];y=fa[y])d2[++t2]=y; for(;x!=y;x=fa[x],y=fa[y])d1[++t1]=x,d2[++t2]=y; g[0]=mx[t1+1]=-2147473647; for(int i=t1;i;i--)mx[i]=max(mx[i+1],v[fa[d1[i]]]); for(int i=1;i<=t1;i++)g[i]=max(g[i-1],f[d1[i]]-mx[i]); id=t1;x=y=-1000000000; for(int i=t2;i;i--) { x=max(x,v[fa[d2[i]]]); for(;id && x>mx[id];id--)y=max(y,f[d1[id]]); f[d2[i]]=max(y-x,g[id])+v[d2[i]]; } } for(x=dfn[n];x;x=fa[x])ans=max(ans,f[x]); printf("%d",ans); return 0; }