1. 程式人生 > >【題解】ZJOI2008騎士

【題解】ZJOI2008騎士

urn 十分 cnp gree arch 沒有 mark target true

樹型打牌:洛谷P2607

這道題目一開始沒有想到解法,只是想到沒有上司的舞會,覺得十分的類似呀。

之後發現:n個點,n條邊,只要刪去一條邊,就變成了和上題一模一樣的做法。

那麽考慮刪去的這條邊,實際上是解除了兩個點之間的限制關系。所以我們只需要分別以他們為根,求出在不取它的情況下所能獲得的最大值。

這是因為這兩種方案顯然只能取其一(這兩個點不能同時取)。

dp[u][0/1]代表是否取當前點的最大值(它&它的子樹)。

#include <bits/stdc++.h>
using namespace std;
#define maxn 1000050
#define int long long
int
n, ans, ath, dep[maxn], mark[maxn], s, cnp = 1, aim, head[maxn], v[maxn], opp[maxn], degree[maxn], dp[maxn][2]; bool vis[maxn]; struct edge { int to, last; }E[maxn]; int read() { int x = 0; char c; c = getchar(); while(c < 0 || c > 9) c = getchar(); while(c >= 0
&& c <= 9) x = x * 10 + c - 0, c = getchar(); return x; } void add(int u, int v) { E[cnp].to = v; E[cnp].last = head[u]; head[u] = cnp ++; } void init() { memset(dp, 0, sizeof(dp)); memset(dep, 0, sizeof(dep)); } void search(int u) { vis[u] = true; for(int
i = head[u]; i; i = E[i].last) { int v = E[i].to; if(dep[v]) continue; dep[v] = dep[u] + 1; search(v); dp[u][0] += max(dp[v][1], dp[v][0]); dp[u][1] += dp[v][0]; } dp[u][1] += v[u]; } void dfs(int u, int fa) { dep[u] = dep[fa] + 1; for(int i = head[u]; i; i = E[i].last) { int v = E[i].to; if(dep[v]) { if(v != fa) aim = u, ath = v; continue; } dfs(v, u); } } signed main() { n = read(); for(int i = 1; i <= n; i ++) { v[i] = read(), opp[i] = read(); degree[opp[i]] ++; if(i == opp[opp[i]]) continue; add(opp[i], i); add(i, opp[i]); } for(int i = 1; i <= n; i ++) { if(vis[i]) continue; init(); ath = aim = 0; dfs(i, 0); init(); if(aim) { dep[aim] = 1; search(aim); int tem = dp[aim][0]; init(); dep[ath] = 1; search(ath); tem = max(tem, dp[ath][0]); ans += tem; } else { dep[i] = 1; search(i); ans += max(dp[i][0], dp[i][1]); } } printf("%lld\n", ans); return 0; }

【題解】ZJOI2008騎士