bzoj1040 騎士

Description

Z國的騎士團是一個頗有勢力的組織,幫會中匯聚了來自各地的精英。他們劫富濟貧,懲惡揚善,受到社會各界的讚賞。最近發生了一件可怕的事情,邪惡的Y國發動了一場針對Z國的侵略戰爭。戰火綿延五百里,在和平環境中安逸了數百年的Z國又怎能抵擋的住Y國的軍隊。因而人們把全部的但願都寄託在了騎士團的身上,就像期待有一個真龍天子的降生,帶領正義戰勝邪惡。騎士團是確定具備戰勝邪惡勢力的能力的,可是騎士們互相之間每每有一些矛盾。每一個騎士都有且僅有一個本身最厭惡的騎士(固然不是他本身),他是絕對不會與本身最厭惡的人一同出征的。戰火綿延,人民生靈塗炭,組織起一個騎士軍團加入戰鬥刻不容緩!國王交給了你一個艱鉅的任務,從全部的騎士中選出一個騎士軍團,使得軍團內沒有矛盾的兩人(不存在一個騎士與他最痛恨的人一同被選入騎士軍團的狀況),而且,使得這支騎士軍團最具備戰鬥力。爲了描述戰鬥力,咱們將騎士按照1至N編號,給每名騎士一個戰鬥力的估計,一個軍團的戰鬥力爲全部騎士的戰鬥力總和。ios

Input

第一行包含一個正整數N,描述騎士團的人數。接下來N行,每行兩個正整數,按順序描述每一名騎士的戰鬥力和他最痛恨的騎士。git

Output

應包含一行,包含一個整數,表示你所選出的騎士軍團的戰鬥力。測試

Sample Input

3
10 2
20 3
30 1

Sample Output

30
「數據規模」
對於30%的測試數據,知足N ≤ 10;
對於60%的測試數據,知足N ≤ 100;
對於80%的測試數據,知足N ≤ 10 000。
對於100%的測試數據,知足N ≤ 1 000 000,每名騎士的戰鬥力都是不大於 1 000 000的正整數。
 
這道題仍是挺難的。
咱們不難想到,若是騎士的憎惡關係是一顆樹的話,就是一道沒有上司的誤會,dp[i][1]表明這個節點取,dp[i][0]表明這個點不取。
若是這個點取,那麼他的兒子必須不取,則:dp[i][1]=Σdp[j][0];
若是這個點不取,那麼他的兒子取不取隨便,則:dp[i][0]=Σmax(dp[j][1],dp[j][0]);
可是!!!!這不是一個樹,而是一個環套樹森林!!
也就是一個樹上多一條邊,有一個環。
咱們對於一個每個環套樹,咱們遍歷找到那個環,而後隨便刪掉一條邊,使這個環套樹變成樹。(具體實現能夠從新建邊)
而後枚舉刪掉這條邊的兩個點,保證一個不取的狀況,有多大價值,而後去這個兩個點分別不取產生價值的max,加入到ans裏面。
而後遍歷森林裏每個環套樹,獲得ans。
 
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#define in(a) a=read()
#define REP(i,k,n)  for(int i=k;i<=n;i++)
#define MAXN 1000010
using namespace std;
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar())
        if(ch=='-')
            f=-1;
    for(;isdigit(ch);ch=getchar())
        x=x*10+ch-'0';
    return x*f;
}
int n,a,b;
long long ans,dp[MAXN][2];
int total,head[MAXN],nxt[MAXN<<1],to[MAXN<<1];
int Total,Head[MAXN],Nxt[MAXN<<1],To[MAXN<<1];
int da,db,vis[MAXN],s[MAXN];
inline void adl(int a,int b){
    total++;
    to[total]=b;
    nxt[total]=head[a];
    head[a]=total;
    return ;
}
inline void Adl(int a,int b){
    Total++;
    To[Total]=b;
    Nxt[Total]=Head[a];
    Head[a]=Total;
    return ;
}
inline void ring(int u,int fa){
    vis[u]=1;
    for(int e=head[u];e;e=nxt[e]){
        if(to[e]==fa)  continue;
        if(vis[to[e]]){
            da=u,db=to[e];
            continue ;
        }
        Adl(u,to[e]),Adl(to[e],u);
        ring(to[e],u);
    }
    return ;
}
inline void dfs(int u,int fa){
    dp[u][1]=s[u],dp[u][0]=0;
    for(int e=Head[u];e;e=Nxt[e]){
        if(To[e]==fa)  continue;
        dfs(To[e],u);
        dp[u][1]+=dp[To[e]][0];
        dp[u][0]+=max(dp[To[e]][0],dp[To[e]][1]);
    }
    return ;
}
inline void solve(int s){
    long long sum1=0,sum2=0;
    da=db=-1;
    ring(s,-1);
    dfs(da,-1),sum1=dp[da][0];
    dfs(db,-1),sum2=dp[db][0];
    ans+=max(sum1,sum2);
    return ;
}
int main(){
    in(n);
    REP(i,1,n)  in(s[i]),in(a),adl(i,a),adl(a,i);
    REP(i,1,n)  if(!vis[i]) solve(i); 
    printf("%lld",ans);
    return 0;
}
相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息