1. 程式人生 > >騎士(樹形dp)

騎士(樹形dp)

題意:給你一個基環樹森林,每個點有一個權值,一條邊上的兩個節點不能同時選擇。選取任意個節點,求最大權值和

 

對於每顆基環樹:找環→斷邊→樹形dp(沒有上司的舞會)

 

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define MAXN 1000005
#define LL long long
using namespace std;

inline 
int read() { int f=1,x=0; char ch=getchar(); while(ch<'0' || ch>'9') {if(ch=='-') f=-1; ch=getchar();} while(ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();} return x*f; } int n,cnt=-1; int val[MAXN]; int v[MAXN<<1],head[MAXN],nxt[MAXN<<1]; int k1,k2,e;
bool book[MAXN]; LL f[MAXN][2],nans,ans; void add(int x,int y) { v[++cnt]=y; nxt[cnt]=head[x]; head[x]=cnt; } void find_circle(int x,int fa) { book[x]=1; for(int i=head[x];i!=-1;i=nxt[i]) { int t=v[i]; if(t==fa) continue; if(book[t]) { k1
=x; k2=t; e=i; continue; } find_circle(t,x); } } void dfs(int x,int fa) { f[x][1]=val[x]; f[x][0]=0; for(int i=head[x];i!=-1;i=nxt[i]) { int t=v[i]; if(i==e || (i^1)==e) continue; if(t==fa) continue; dfs(t,x); f[x][0]+=max(f[t][0],f[t][1]); f[x][1]+=f[t][0]; } } int main() { memset(head,-1,sizeof(head)); int i; int x; n=read(); for(i=1;i<=n;i++) { val[i]=read(); x=read(); add(i,x); add(x,i); } for(i=1;i<=n;i++) { if(!book[i]) { find_circle(i,-1); dfs(k1,-1); nans=f[k1][0]; dfs(k2,-1); nans=max(nans,f[k2][0]); ans+=nans; } } printf("%lld",ans); return 0; }