传送门:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1040

 

n个点,n条边的无向图,求最大权和独立集,乍看之下不可做,但实际本题有一个特殊的性质,即一个骑士只有一个他最痛恨的人,

这样就表明了图中的环没有公共点,那么我们就可以进行环套树dp,将以环上每个点为根的树dp找出最优值,再把环拆成链,记录

链首是否选择,就可以了。

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <list>
#include <queue>
using namespace std;
typedef long long LL;
const int maxn = 1000010;
list <int> edge[maxn];
int a[maxn], cnt[maxn];
LL f[maxn][2], g[maxn][2][2];
bool vis[maxn];
int n;
LL ans;
queue <int> q;
void get(int &tmp) {
    tmp = 0;
    char ch = getchar();
    for(; ch < '0' || ch > '9'; ch = getchar());
    for(; ch >= '0' && ch <= '9'; ch = getchar()) tmp = tmp * 10 + ch - '0';
    return;
}
void dp(int x) {
    f[x][1] += (LL)a[x];
    g[x][0][0] = f[x][0]; g[x][1][1] = f[x][1];
    int nxt = 0;
    for(list <int> :: iterator p = edge[x].begin(); p != edge[x].end(); p ++) {
        if(!vis[*p]) {
            nxt = *p; break;
        }
    }
    while(nxt) {
        vis[x] = true;
        f[nxt][1] += (LL)a[nxt];
        g[nxt][0][0] = max(g[x][0][0], g[x][1][0]) + f[nxt][0];
        g[nxt][1][0] = g[x][0][0] + f[nxt][1];
        g[nxt][0][1] = max(g[x][0][1], g[x][1][1]) + f[nxt][0];
        g[nxt][1][1] = g[x][0][1] + f[nxt][1];
        int tmp = 0;
        for(list <int> :: iterator p = edge[nxt].begin(); p != edge[nxt].end(); p ++) {
            if(!vis[*p]) {
                tmp = *p;
                break;
            }
        }
        x = nxt; nxt = tmp;
    }
    vis[x] = true;
    ans += max(g[x][0][0], max(g[x][1][0], g[x][0][1]));
    return;
}
int main() {
    get(n);
    int v;
    for(int i = 1; i <= n; i ++) {
        get(a[i]); get(v);
        edge[i].push_back(v);
        edge[v].push_back(i);
        cnt[i] ++; cnt[v] ++;
    }
    for(int i = 1; i <= n; i ++) {
        if(cnt[i] == 1) q.push(i);
    }
    while(!q.empty()) {
        int t = q.front();
        q.pop();
        f[t][1] += (LL)a[t];
        for(list <int> :: iterator p = edge[t].begin(); p != edge[t].end(); p ++) {
            if(!vis[*p]) {
                f[*p][0] += max(f[t][0], f[t][1]);
                f[*p][1] += f[t][0];
                cnt[*p] --;
                if(cnt[*p] == 1) q.push(*p);
            }
        }
        vis[t] = true;
    }
    for(int i = 1; i <= n; i ++) {
        if(!vis[i]) dp(i);
    }
    cout << ans << endl;
    return 0;
}