bzoj1040 基环树森林dp

https://www.lydsy.com/JudgeOnline/problem.php?id=1040

  Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英。他们劫富济贫,惩恶扬善,受到社会各
界的赞扬。最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的侵略战争。战火绵延五百里,在和平环境
中安逸了数百年的Z国又怎能抵挡的住Y国的军队。于是人们把所有的希望都寄托在了骑士团的身上,就像期待有一
个真龙天子的降生,带领正义打败邪恶。骑士团是肯定具有打败邪恶势力的能力的,但是骑士们互相之间往往有一
些矛盾。每个骑士都有且仅有一个自己最厌恶的骑士(当然不是他自己),他是绝对不会与自己最厌恶的人一同出
征的。战火绵延,人民生灵涂炭,组织起一个骑士军团加入战斗刻不容缓!国王交给了你一个艰巨的任务,从所有
的骑士中选出一个骑士军团,使得军团内没有矛盾的两人(不存在一个骑士与他最痛恨的人一同被选入骑士军团的
情况),并且,使得这支骑士军团最具有战斗力。为了描述战斗力,我们将骑士按照1至N编号,给每名骑士一个战
斗力的估计,一个军团的战斗力为所有骑士的战斗力总和。

Input
  第一行包含一个正整数N,描述骑士团的人数。接下来N行,每行两个正整数,按顺序描述每一名骑士的战斗力
和他最痛恨的骑士。

Output
  应包含一行,包含一个整数,表示你所选出的骑士军团的战斗力。

Sample Input
3
10 2
20 3
30 1
Sample Output
30
Hint
N ≤ 1 000 000,每名骑士的战斗力都是不大于 1 000 000的正整数。
题意

 

求解最大点独立集的大小,但是这个数据范围是不能求解的,仔细一看会发现题目给的是一片基环树森林,所以我们考虑对每一棵基环树进行树形dp,求他的总和。

 

求解基环树问题一般来说是将环看作广义上的根节点然后求解,对于这道题事实上唯一的限制条件就是环上两个相邻的点之间不能同时取到,所以我们考虑断开环变成一棵树,g[u]表示根节点为u时,u不取的最大值,所以单独一颗基环树的最大值就是环上任意边的两相邻点g[u],g[v]的较大值。

然后用简单树dp即可求解。

 

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
inline int read(){int now=0;register char c=getchar();for(;!isdigit(c);c=getchar());
for(;isdigit(c);now=now*10+c-'0',c=getchar());return now;}
#define For(i, x, y) for(int i=x;i<=y;i++)  
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))  
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x);  
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);  
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long  
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second 
typedef vector<int> VI;
const double eps = 1e-9;
const int maxn = 1e6 + 10;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7; 
int N,M,K;
LL v[maxn];
LL f[maxn],g[maxn]; 
int head[maxn],tot;
struct Edge{
    int to,next;
}edge[maxn * 2];
void init(){
    Mem(head,-1); tot = 0;
}
void add(int u,int v){
    edge[tot].to = v; edge[tot].next = head[u];
    head[u] = tot++;
}
int U,V,E;
bool vis[maxn];
void dfs(int t,int fa){
    vis[t] = 1;
    for(int i = head[t]; ~i; i = edge[i].next){
        int v = edge[i].to;
        if(v == fa) continue;
        if(vis[v]){
            U = t; V = v;
            E = i;
            continue;
        }
        dfs(v,t);
    }
}
void DP(int t,int fa,int del){
    f[t] = v[t]; g[t] = 0;
    for(int i = head[t]; ~i; i = edge[i].next){
        int v = edge[i].to;
        if((i == del) || (v == fa) || ((i ^ 1) == del)) continue;
        DP(v,t,del);
        g[t] += max(f[v],g[v]);
        f[t] += g[v];
    }
}
int main()
{
    Sca(N); init();
    For(i,1,N){
        Scl(v[i]); int x = read();
        add(x,i); add(i,x);
    }
    LL ans = 0;
    For(i,1,N){
        if(!vis[i]){
            dfs(i,0);
            DP(U,0,E); LL MAX = g[U];
            DP(V,0,E); MAX = max(MAX,g[V]);
            ans += MAX;
        }
    }
    Prl(ans);
    #ifdef VSCode
    system("pause");
    #endif
    return 0;
}

 

posted @ 2018-10-25 13:30  Hugh_Locke  阅读(200)  评论(0编辑  收藏  举报