bozj1040: [ZJOI2008] Knight (Odd Ring Tree, DP)


1040: [ZJOI2008] Knight


Let's suppose that knight (u\) hates Knights (v\), and we connect a side between (u\) and (v\), so that we get a odd ring tree (odd ring forest). Since it is a odd ring tree, we first consider the disconnection of the ring. The two points connected to the open edge are rt1\ (, rt1\), (rt2\).

According to the meaning of the question, what we need is the maximum value when two adjacent nodes can not be selected at the same time, which is not the odd ring tree version. A dance without a supervisor Do you?

So it's easy to get the transfer equation.
Let(f[u][1/0] denote the maximum value that can be obtained by choosing/not choosing\as the root.
\[\begin{cases} f[u][1] += f[v][0]\\\\ f[u][0] += max(f[v][0], f[v][1]) \end{cases}\]

Then use(rt1) and(rt2) as roots for tree DP, respectively.

Because \(rt1) and \(rt2\) are two points on the ring, they can not be selected at the same time. We force (rt1), (rt2\) not to be selected, and accumulate the maximum value.

The original picture may be the Qihuan Forest, so mark each point with vis to see if it has been visited.


#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e6 + 10;
int n, m, num = 1, rt1, rt2, flag, ans, kk;
int head[N], f[N][2], a[N];
bool vis[N], vis2[N];
struct node {
    int v, nx;
} e[N];
template<class T>inline void read(T &x) {
    x = 0; int f = 0; char ch = getchar();
    while (!isdigit(ch)) f |= (ch == '-'), ch = getchar();
    while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
    x = f ? -x : x;
inline void add(int u, int v) {
    e[++num] = (node) {v, head[u]}, head[u] = num;
void FindCircle(int u, int fa) {
    vis[u] = 1;
    for (int i = head[u]; ~i; i = e[i].nx) {
        int v = e[i].v;
        if (v == fa) continue;
        if (!vis[v]) FindCircle(v, u);
        else {
            rt1 = u, rt2 = v;
            kk = i;
void dfs(int u, int fa) {
    f[u][1] = a[u];
    for (int i = head[u]; ~i; i = e[i].nx) {
        int v = e[i].v;
        if (v == fa || i == kk || (i ^ 1) == kk) continue;
        dfs(v, u);
        f[u][1] += f[v][0];
        f[u][0] += max(f[v][1], f[v][0]);
signed main() {
    memset(head, -1, sizeof head);
    for (int i = 1, x; i <= n; ++i) {
        read(a[i]), read(x);
        add(i, x), add(x, i);
    for (int i = 1; i <= n; ++i) {
        if (vis[i]) continue;
        int tmp = 0;
        FindCircle(i, -1);
        memset(f, 0, sizeof f);
        dfs(rt1, -1);
        tmp = max(tmp, f[rt1][0]);
        memset(f, 0, sizeof f);
        dfs(rt2, -1);
        tmp = max(tmp, f[rt2][0]);
        ans += tmp;
    cout << ans << endl;

Tags: C++ supervisor

Posted on Wed, 02 Oct 2019 03:29:58 -0400 by dey.souvik007