首先,建出来的是无向图,因为a看不上b他们一定不会一起被选出。。。
然后,n个点n条边,形成的是环套树森林
于是有个奇技淫巧的做法,先dfs一遍找到环上的两个点,然后拆掉那条边,记下来边的两端x, y两个节点
强制x为根且x不选做树形动规,然后强制y为根且y不选再做一遍树形动规,两次的最大值加入答案
注意写法,我记录了father就找不到二元环的情况了QAQQQ,WA到死。。。要记录来的那条边
1 /************************************************************** 2 Problem: 1040 3 User: rausen 4 Language: C++ 5 Result: Accepted 6 Time:1992 ms 7 Memory:51724 kb 8 ****************************************************************/ 9 10 #include <cstdio> 11 #include <algorithm> 12 13 using namespace std; 14 const int N = 1e6 + 5; 15 16 struct edge { 17 int next, to, f; 18 edge() {} 19 edge(int _n, int _t, int _f = 1) : next(_n), to(_t), f(_f) {} 20 } e[N << 1]; 21 22 int n, rt1, rt2; 23 int first[N], tot = 1; 24 int v[N], vis[N]; 25 long long f[N][2], ans; 26 27 inline int read() { 28 int x = 0; 29 char ch = getchar(); 30 while (ch < '0' || '9' < ch) 31 ch = getchar(); 32 while ('0' <= ch && ch <= '9') { 33 x = x * 10 + ch - '0'; 34 ch = getchar(); 35 } 36 return x; 37 } 38 39 inline void Add_Edges(int x, int y) { 40 e[++tot] = edge(first[x], y), first[x] = tot; 41 e[++tot] = edge(first[y], x), first[y] = tot; 42 } 43 44 #define y e[x].to 45 void dfs(int p, int from) { 46 int x; 47 vis[p] = 1; 48 for (x = first[p]; x; x = e[x].next) 49 if (!vis[y]) dfs(y, x); 50 else if ((from ^ 1) != x && !rt1) 51 rt1 = p, rt2 = y, e[x].f = e[x ^ 1].f = 0; 52 } 53 54 void dp(int p, int t) { 55 int x; 56 vis[p] = t; 57 f[p][0] = 0, f[p][1] = v[p]; 58 for (x = first[p]; x; x = e[x].next) 59 if (vis[y] != t && e[x].f) { 60 dp(y, t); 61 f[p][0] += max(f[y][0], f[y][1]); 62 f[p][1] += f[y][0]; 63 } 64 } 65 #undef y 66 67 int main() { 68 int i; 69 long long tmp; 70 n = read(); 71 for (i = 1; i <= n; ++i) 72 v[i] = read(), Add_Edges(read(), i); 73 for (i = 1; i <= n; ++i) 74 if (!vis[i]) { 75 rt1 = rt2 = 0; 76 dfs(i, 0); 77 dp(rt1, 2), tmp = f[rt1][0]; 78 dp(rt2, 3), ans += max(tmp, f[rt2][0]); 79 } 80 printf("%lld\n", ans); 81 return 0; 82 }
By Xs酱~ 转载请说明
博客地址:http://www.cnblogs.com/rausen