[BZOJ1040][ZJOI2008]騎士(樹形DP)
阿新 • • 發佈:2018-06-03
sans spa mic AR mil getc bzoj 一個 lin
對於一個聯通塊內,有且只有一個環,即n個點n條邊
那麽找到那個環,然後任意斷一條邊,這個聯通塊就變成一棵樹了,然後做樹形DP就行了
對於斷的邊要記錄下來DP時特判
Code
#include <cstdio> #include <algorithm> #include <cstring> #define ll long long #define N 1000010 using namespace std; struct info{int to,nex;}e[N*2]; int n,A[N],tot=1,head[N],x,y,ee; ll Ans,dp[N][2]; bool vis[N]; void Link(int u,int v){ e[++tot].nex=head[u];head[u]=tot;e[tot].to=v; } inline int read(){ int x=0,f=1;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; } bool Fvis[N]; void Find(int u,int fa){ Fvis[u]=1; for(int i=head[u],v;i;i=e[i].nex){ if((v=e[i].to)==fa) continue; if(Fvis[v]) x=u,y=v,ee=i; else Find(v,u); } } void DP(int u,int fa){ vis[u]=1; dp[u][0]=0,dp[u][1]=A[u]; for(int i=head[u],v;i;i=e[i].nex){ if((v=e[i].to)!=fa&&i!=ee&&(i^1)!=ee){ DP(v,u); dp[u][1]+=dp[v][0]; dp[u][0]+=max(dp[v][0],dp[v][1]); } } } void solve(int u){ if(vis[u]) return; vis[u]=1; memset(Fvis,0,sizeof(Fvis)); Find(u,0); DP(x,0); ll t=dp[x][0]; DP(y,0); Ans+=max(t,dp[y][0]); } int main(){ n=read(); for(int i=1,x;i<=n;++i) A[i]=read(),Link(x=read(),i),Link(i,x); for(int i=1;i<=n;solve(i++)); printf("%lld\n",Ans); return 0; }
[BZOJ1040][ZJOI2008]騎士(樹形DP)