BZOJ1040: [ZJOI2008]骑士 (树形DP)

题意:1e6个骑士 每个骑士有一个战斗力有一个讨厌的人

   选择一些人组成军团使得军团战斗力和最大 且每个人不会和自己讨厌的人都在军团里

题解:每个点和自己讨厌的点建一条双向边 因为你讨厌他 你不会和他同时出现

   n个点n条边 那么每一个独立的子集都是一棵带环树

   先dfs一遍找到形成环的地方 把他断掉

   分别以两个点做一次不能选相邻两个点的树形DP 且不选起点

总结:树上的操作还是不熟 怎么找环断开边什么的

 

#include <stdio.h>
#include <algorithm>
#include <iostream>
#include <string.h>
using namespace std;
typedef long long ll;

int n;
struct node
{
    int to, nex;
}E[2000005];

int head[2000005];
int vis[1000005];
int s[2000005];
ll q[1000005];
ll dp[1000005][3];
int l, r;
bool f;

void dfs(int x, int fa)
{
    vis[x] = 1;

    int c = head[x];
    for(int i = c; i && (!f); i = E[i].nex)
    {
        int v = E[i].to;
        if(v == fa) continue;

        if(vis[v])
        {
            s[i] = -1;      //表示将这两条边断开
            if((i & 1) == 1) s[i + 1] = -1;
            else s[i - 1] = -1;

            l = x; r = v; f = true;
            break;
        }
        dfs(v, x);
    }
}

void dfs1(int x, int fa, int cut)
{
    vis[x] = true;       //可能找到环了 但这颗带环树还没搜完
    if(x != cut) dp[x][1] = q[x];
    else dp[x][1] = 0;
    dp[x][0] = 0;

    int c = head[x];
    for(int i = c; i; i = E[i].nex)
    {
        int v = E[i].to;
        if(v == fa) continue;
        if(s[i] == -1) continue;

        dfs1(v, x, cut);
        dp[x][1] += dp[v][0];
        dp[x][0] += max(dp[v][1], dp[v][0]);
    }
}

int main()
{
    int cnt = 0;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
    {
        int x;
        scanf("%lld%d", &q[i], &x);
        E[++cnt].to = x, E[cnt].nex = head[i], head[i] = cnt;
        E[++cnt].to = i, E[cnt].nex = head[x], head[x] = cnt;
    }

    ll ans = 0;
    for(int i = 1; i <= n; i++)
    {
        if(!vis[i])
        {
            f = false;      //任意独立x个点x条边 一定带环 所以不存在树了
            dfs(i, -1);

            ll o = 0;
            dfs1(l, -1, r);
            o = max(o, dp[l][0]); o = max(o, dp[l][1]);
            dfs1(r, -1, l);
            o = max(o, dp[r][0]); o = max(o, dp[r][1]);
            ans += o;
        }
    }
    printf("%lld\n", ans);

    return 0;
}
/*
5
10 2
10 3
10 4
10 2
10 4
5
10 2
25 3
10 4
16 2
10 4
*/
View Code

 

posted @ 2018-05-21 09:58  lwqq3  阅读(148)  评论(0编辑  收藏  举报