BZOJ 1040 [ZJOI2008]骑士

内向树dp~

就是先找环,任取环上有边相连两点,u和v,以u为根,断开u和v之间的边,做两次树形dp,dp[i][0]表示i不选,dp[i][1]表示i选

①强制u不选,v随意

②u随意,v不选

两种情况取最大值即可~

 

View Code
 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <cstdlib>
 5 #include <algorithm>
 6 
 7 #define N 2000000
 8 #define M 4000000
 9 
10 using namespace std;
11 
12 int head[N],next[M],to[M],bh[N];
13 int n,ban,rp,cnt,root;
14 long long val[N],ans,res,dp[N][2];
15 bool vis[N],v[N];
16 
17 inline void add(int u,int v)
18 {
19     to[cnt]=v; next[cnt]=head[u]; head[u]=cnt++;
20 }
21 
22 inline void read()
23 {
24     memset(head,-1,sizeof head); cnt=0;
25     scanf("%d",&n);
26     for(int i=1,a;i<=n;i++)
27     {
28         scanf("%lld%d",&val[i],&a);
29         add(i,a); add(a,i);
30     }
31 }
32 
33 inline void circle(int u,int fa)
34 {
35     for(int i=head[u];~i;i=next[i])
36     {
37         if(!bh[to[i]])
38         {
39             bh[to[i]]=true;
40             circle(to[i],u);
41         }
42         else if(to[i]!=fa) rp=u,root=to[i],ban=i;
43     }
44 }
45 
46 inline void dfscir(int u)
47 {
48     dp[u][0]=0; dp[u][1]=val[u];
49     for(int i=head[u];~i;i=next[i])
50         if(i!=ban&&(i^1)!=ban&&!vis[to[i]])
51         {
52             vis[to[i]]=true;
53             dfscir(to[i]);
54             dp[u][1]+=dp[to[i]][0];
55             dp[u][0]=max(dp[to[i]][0],dp[to[i]][1])+dp[u][0];
56         }
57 }
58 
59 inline void dfsban(int u)
60 {
61     dp[u][0]=0; dp[u][1]=val[u];
62     for(int i=head[u];~i;i=next[i])
63         if(i!=ban&&(i^1)!=ban&&!v[to[i]])
64         {
65             v[to[i]]=true;
66             dfsban(to[i]);
67             dp[u][1]+=dp[to[i]][0];
68             if(to[i]==rp) dp[u][0]+=dp[to[i]][0];
69             else dp[u][0]+=max(dp[to[i]][0],dp[to[i]][1]);
70         }
71 }
72 
73 inline void go()
74 {
75     for(int i=1;i<=n;i++)
76         if(!bh[i])
77         {
78             root=-1;bh[i]=true;
79             circle(i,-1);
80             vis[root]=true; dfscir(root); res=dp[root][0];
81             v[root]=true; dfsban(root); res=max(res,max(dp[root][0],dp[root][1]));
82             ans+=res;
83         }
84     printf("%lld\n",ans);
85 }
86 
87 int main()
88 {
89     read();
90     go();
91     return 0;
92 }

 

 

posted @ 2013-01-18 22:49  proverbs  阅读(1361)  评论(0编辑  收藏  举报