BZOJ 1040 ZJOI 2008 骑士 树形DP

题意:

有一些战士,他们有战斗力和讨厌的人,选择一些战士,使他们互不讨厌,且战斗力最大,范围1e6

分析:

把战士看作点,讨厌的关系看作一条边,连出来的是一个基环树森林。

对于一棵基环树,我们找出环,选择环上一条边(u,v)。

那么只需考虑两种情况:1、u不选,v任意;2、v不选,u任意。答案取max累计即可

程序:

 1 #include <cstdio>
 2 #include <cstdlib>
 3 #include <cstring>
 4 #include <string>
 5 #include <algorithm>
 6 #include <iostream>
 7 
 8 using namespace std;
 9 
10 #define REP(i, a, b) for (int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
11 #define mset(a, b) memset(a, b, sizeof(a))
12 #define max_(a, b) a > b ? a : b
13 const int maxn = 1e6+10;
14 typedef long long LL;
15 int n;
16 struct Edge
17 {
18     int v, nxt;
19     Edge (int v = 0, int nxt = 0):
20         v(v), nxt(nxt) {}
21 }e[maxn*2];
22 int head[maxn], label;
23 int U, V, E, w[maxn];
24 bool vis[maxn];
25 LL f[maxn][2];
26 
27 template <class TAT>
28 void Ckmax(TAT &a, const TAT &b)
29 {
30     if (a < b) a = b;
31 }
32 
33 void ins(int u, int v)
34 {
35     e[++label] = Edge(v, head[u]), head[u] = label;
36     e[++label] = Edge(u, head[v]), head[v] = label;
37 }
38 
39 void dfs(int u, int fa)
40 {
41     for (int i = head[u]; i != -1; i = e[i].nxt)
42     {
43         int v = e[i].v;
44         if (v == fa) continue ;
45         if (vis[v])
46         {
47             U = u, V = v, E = i;
48             continue ;
49         }
50         vis[v] = true;
51         dfs(v, u);
52     }
53 }
54 
55 void work(int u, int fa, int ban)
56 {
57     f[u][0] = 0, f[u][1] = w[u];
58     for (int i = head[u]; i != -1; i = e[i].nxt)
59     {
60         int v = e[i].v;
61         if (v == fa || i == ban || i == (ban^1)) continue ;
62         work(v, u, ban);
63         f[u][0] += max_(f[v][0], f[v][1]);
64         f[u][1] += f[v][0];
65     }
66 }
67 
68 int main()
69 {
70     scanf("%d", &n);
71     REP(i, 1, n) head[i] = -1;
72     label = -1;
73     REP(i, 1, n)
74     {
75         int v;
76         scanf("%d %d", &w[i], &v);
77         ins(i, v);
78     }
79     mset(vis, 0), mset(f, 0);
80     LL ans = 0;
81     REP(i, 1, n)
82         if (!vis[i])
83         {
84             vis[i] = true, dfs(i, 0);
85             LL temp;
86             work(U, 0, E);
87             temp = f[U][0];
88             work(V, 0, E);
89             Ckmax(temp, f[V][0]);
90             ans += temp;
91         }
92     printf("%lld\n", ans);
93     return 0;
94 }
View Code

 

posted @ 2017-03-20 10:46  Splay  阅读(179)  评论(0编辑  收藏  举报