n个点n条边,说明图中存在一个简单环,更准确的说是每一个连通块中存在一个简单环(因为图可能不连通)。
然后有人给这个玩意起了个名字:基环外向树。
然而并没有什么用。
思路很简单:断环为链,就变成了一棵树了。为了防止断开的两端(x, y)同时被选,从x和y分别树形dp一下,然后硬性规定根节点不能选即可。
树形dp就不说啦,就是没有上司的舞会。
需要注意的是,找环不仅要记录端点,还要记录断开的边E。然后E和E ^ 1就是断开的边。
1 #include2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 #include 10 #include 11 using namespace std; 12 #define enter puts("") 13 #define space putchar(' ') 14 #define Mem(a, x) memset(a, x, sizeof(a)) 15 #define rg register 16 typedef long long ll; 17 typedef double db; 18 const int INF = 0x3f3f3f3f; 19 const db eps = 1e-8; 20 const int maxn = 1e6 + 5; 21 inline ll read() 22 { 23 ll ans = 0; 24 char ch = getchar(), last = ' '; 25 while(!isdigit(ch)) {last = ch; ch = getchar();} 26 while(isdigit(ch)) {ans = (ans << 1) + (ans << 3) + ch - '0'; ch = getchar();} 27 if(last == '-') ans = -ans; 28 return ans; 29 } 30 inline void write(ll x) 31 { 32 if(x < 0) x = -x, putchar('-'); 33 if(x >= 10) write(x / 10); 34 putchar(x % 10 + '0'); 35 } 36 37 int n, a[maxn]; 38 39 struct Edge 40 { 41 int nxt, to; 42 }e[maxn << 1]; 43 int head[maxn], ecnt = -1; 44 void addEdge(int x, int y) 45 { 46 e[++ecnt] = (Edge){head[x], y}; 47 head[x] = ecnt; 48 } 49 50 int rt1, rt2, E; //E, E ^ 1:the edge wich is cutted 51 bool vis[maxn], cir[maxn]; 52 void Find(int now, int _e) 53 { 54 vis[now] = cir[now] = 1; 55 for(int i = head[now], v; i != -1; i = e[i].nxt) 56 { 57 v = e[i].to; 58 if(cir[v] && i != (_e ^ 1)) 59 { 60 rt1 = now; rt2 = v; E = i; 61 } 62 if(!vis[v]) Find(v, i); 63 } 64 cir[now] = 0; 65 } 66 67 ll dp[maxn][2]; 68 void dfs(int now, int f) 69 { 70 dp[now][0] = dp[now][1] = 0; 71 for(int i = head[now], v; i != -1; i = e[i].nxt) 72 { 73 v = e[i].to; 74 if(v == f || i == E || i == (E ^ 1)) continue; 75 dfs(v, now); 76 dp[now][1] += dp[v][0]; 77 dp[now][0] += max(dp[v][1], dp[v][0]); 78 } 79 dp[now][1] += a[now]; 80 } 81 82 int main() 83 { 84 Mem(head, -1); 85 n = read(); 86 for(int i = 1; i <= n; ++i) 87 { 88 a[i] = read(); 89 int x = read(); addEdge(i, x); addEdge(x, i); 90 } 91 ll ans = 0; 92 for(int i = 1; i <= n; ++i) if(!vis[i]) 93 { 94 Find(i, -1); 95 dfs(rt1, 0); 96 ll Max = 0; 97 if(dp[rt1][0] > Max) Max = dp[rt1][0]; 98 dfs(rt2, 0); 99 if(dp[rt2][0] > Max) Max = dp[rt2][0];100 ans += Max;101 }102 write(ans), enter;103 return 0;104 }