BZOJ 1040 树形DP+环套树

就是有n个点n条边,那么有且只有一个环那么用Dfs把在环上的两个点找到。然后拆开,从这条个点分别作树形Dp即可.

 1  
 2 #include <cstdio>
 3 #include <cstring>
 4 #define LL long long
 5 const LL Maxn=1001000;
 6 struct Edge{LL to,next;}edge[Maxn<<2];
 7 LL head[Maxn],F[Maxn],G[Maxn],cnt,U,V,E,vis[Maxn],a[Maxn],n,Ans;
 8 inline void Add(LL u,LL v) {edge[++cnt].to=v;edge[cnt].next=head[u];head[u]=cnt;}
 9 inline LL Max(LL x,LL y) {return x>y?x:y;}
10 void Dfs(LL u,LL fa)
11 {
12     vis[u]=true;
13     for (LL i=head[u];i!=-1;i=edge[i].next)
14     {
15         if (edge[i].to==fa) continue;
16         if (vis[edge[i].to])
17         {
18             U=u,V=edge[i].to;
19             E=i;
20             continue;
21         }
22         Dfs(edge[i].to,u);
23     }
24 }
25 void Dp(LL u,LL fa,LL Ban)
26 {
27     F[u]=a[u],G[u]=0;
28     for (LL i=head[u];i!=-1;i=edge[i].next)
29     {
30         if (i==Ban || (i^1)==Ban || edge[i].to==fa) continue;
31         Dp(edge[i].to,u,Ban);
32         F[u]+=G[edge[i].to];
33         G[u]+=Max(F[edge[i].to],G[edge[i].to]);
34     }
35 }
36  
37 int main()
38 {
39     scanf("%lld",&n);
40     memset(head,-1,sizeof(head)); cnt=1;
41     for (LL i=1;i<=n;i++) 
42     {
43         LL u;
44         scanf("%lld%lld",&a[i],&u);
45         Add(u,i),Add(i,u);
46     }
47      
48     for (LL i=1;i<=n;i++)
49         if (!vis[i])
50         {
51             Dfs(i,0);
52             Dp(U,0,E);
53             LL Ret=G[U];
54             Dp(V,0,E);
55             Ret=Max(Ret,G[V]);
56             Ans+=Ret;
57         }
58     printf("%lld
",Ans);
59     return 0;
60 }
C++
原文地址:https://www.cnblogs.com/yyjxx2010xyu/p/5684513.html