1. 程式人生 > >三校聯考20181024T2 點亮light

三校聯考20181024T2 點亮light

題意: 題面 子任務

題解: 首先bb一下,本蒟蒻即將被第4個學校的dalao們吊打。 wor,考場上做這道題時接連看錯兩次題意,簡直差點自閉,還好暴力分給得足。 然後吐槽一下題解的玄學程度…如果臉黑的話隨機出來的資料真的還跑得過?算了就假設出資料的人沒那麼非,所有資料中樹的深度就是期望深度=1+i=1n1i=1+lnn+Θ(1)=1+\displaystyle \sum_{i=1}^n{\dfrac{1}{i}}=1+\ln n+\Theta(1),子樹大小就是期望大小nu\le \dfrac{n}{u}。證明過程略。其實是我自己太菜了證不來

樹形dp是一個很容易想到的方向,但具體怎麼實現還是有點噁心。我們很容易想到dp[i][j]為以i為根的子樹上亮了j個點的答案。但是狀態還要考慮到從1到i的路徑上的情況,而如果強行記在狀態裡面的話存不下,那就一邊dfs一邊存狀態。把所有a[u][v],b[u][v]都加到lca(u,v)上作為u與lca(u,v)之間的點權,然後求出從1到u的狀態為s時u的貢獻。然後在樹上跑個揹包即可。

程式碼:

#include<cstdio>
#include<cstring>
#define maxn 1005
#define D 10
#define INF 0x3f3f3f3f
int
n,dp[maxn][maxn],fa[maxn][D],l[maxn][maxn],dep[maxn],siz[maxn],ans,val[maxn][maxn][2],sta[maxn]; struct node { int v; node *nxt; } edge[maxn],*head[maxn],*ncnt; inline int max(int a,int b) { return a>b?a:b; } void swap(int &a,int &b) { int t=a; a=b,b=t; } void addedge(int u,int v) { ncnt++
; ncnt->v=v,ncnt->nxt=head[u]; head[u]=ncnt; } void dfs1(int u,int d) { siz[u]=1,dep[u]=d; for(node *p=head[u];p;p=p->nxt) { dfs1(p->v,d+1); siz[u]+=siz[p->v]; } } int lca(int u,int v) { if(dep[u]<dep[v]) swap(u,v); int t; for(t=0;(1<<t)<=dep[u];t++); t--; for(;t>=0;t--) if(dep[fa[u][t]]>=dep[v]) u=fa[u][t]; if(u==v) return u; for(t=0;(1<<t)<=dep[u];t++); t--; for(;t>=0;t--) if(fa[u][t]!=fa[v][t]) u=fa[u][t],v=fa[v][t]; return fa[u][0]; } void dfs2(int u,int fa,int d) { int tmp[maxn]; for(int i=0;i<=siz[u];i++) dp[u][i]=-INF; sta[d]=1,dp[u][1]=0; for(int i=1;i<=d;i++) if(sta[i]) dp[u][1]+=val[u][i][1]; if(siz[u]>1) { dp[u][0]=0; for(int i=1;i<=d;i++) if(!sta[i]) dp[u][0]+=val[u][i][0]; } for(node *p=head[u];p;p=p->nxt) { int v=p->v; dfs2(v,u,d+1); for(int i=siz[u];i>=0;i--) { dp[u][i]+=dp[v][0]; for(int j=1;j<=siz[v]&&j<=i;j++) dp[u][i]=max(dp[u][i],dp[u][i-j]+dp[v][j]); } } memcpy(tmp,dp[u],sizeof(dp[u])); for(int i=0;(i<<1)<siz[u];i++) tmp[i]=-INF; for(int i=0;i<=siz[u];i++) dp[u][i]=-INF; sta[d]=0; if(siz[u]>1) { dp[u][1]=0; for(int i=1;i<=d;i++) if(sta[i]) dp[u][1]+=val[u][i][1]; } dp[u][0]=0; for(int i=1;i<=d;i++) if(!sta[i]) dp[u][0]+=val[u][i][0]; for(node *p=head[u];p;p=p->nxt) { int v=p->v; dfs2(v,u,d+1); for(int i=siz[u];i>=0;i--) { dp[u][i]+=dp[v][0]; for(int j=1;j<=siz[v]&&j<=i;j++) dp[u][i]=max(dp[u][i],dp[u][i-j]+dp[v][j]); } } for(int i=(siz[u]+1)>>1;i<=siz[u];i++) dp[u][i]=-INF; for(int i=0;i<=siz[u];i++) dp[u][i]=max(dp[u][i],tmp[i]); } void read(int &x) { char ch=getchar(); int f=1; x=0; while((ch<'0'||ch>'9')&&ch!='-') ch=getchar(); if(ch=='-') f=-1,ch=getchar(); for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+f*(ch-'0'); } int main() { scanf("%d",&n); ncnt=&edge[0]; for(int i=2;i<=n;i++) { read(fa[i][0]); addedge(fa[i][0],i); } dfs1(1,1); for(int j=1;j<D;j++) for(int i=1;i<=n;i++) fa[i][j]=fa[fa[i][j-1]][j-1]; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) l[i][j]=l[j][i]=lca(i,j); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(i!=j) { int a,b; read(a); read(b); val[i][dep[l[i][j]]][0]+=a;val[i][dep[l[i][j]]][1]+=b; } dfs2(1,0,1); for(int i=0;i<=n;i++) ans=max(ans,dp[1][i]); printf("%d\n",ans); }