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 }
没有人能阻止我前进的步伐,除了我自己!