首页 > 代码库 > bzoj 1040: [ZJOI2008]骑士 環套樹DP

bzoj 1040: [ZJOI2008]骑士 環套樹DP

1040: [ZJOI2008]骑士

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 1755  Solved: 690
[Submit][Status]

Description

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

Input

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

Output

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

Sample Input

3
10 2
20 3
30 1

Sample Output

30

HINT

 

对于100%的测试数据,满足N ≤ 1 000 000,每名骑士的战斗力都是不大于   1 000 000的正整数。

 

Source

   ╮(╯▽╰)╭ 網上說什麼外向樹內向樹,完全不懂,說白了,這道題就是一個環套樹DP,由於每個人只貢獻一條邊,所以最終圖的結構只會是一系列包含一個環的聯通快,在這些聯通塊上分別做環套樹DP就行了。

  這道題環套樹DP非常簡單,直接隨機選環上一條邊刪掉,然後特殊處理刪掉邊的兩個端點,使之不被選擇,然後在樹上DP即可。

  這是我第一次編環套樹。

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<ctime>#include<cmath>#include<algorithm>#include<set>#include<map>#include<vector>#include<string>#include<queue>using namespace std;#ifdef WIN32#define LL "%I64d"#else#define LL "%lld"#endif#define MAXN 1100000#define MAXV MAXN*2#define MAXE MAXV*2#define INF 0x3f3f3f3f#define INFL 0x00003f3f3f3f3f3fLLtypedef long long qword;inline int nextInt(){        char ch;        int x=0;        bool flag=false;        do                ch=getchar(),flag=(ch==-)?true:flag;        while(ch<0||ch>9);        do x=x*10+ch-0;        while (ch=getchar(),ch<=9 && ch>=0);        return x*(flag?-1:1);}int n,m;int e[MAXN][3];struct Edge{        int np;        Edge *next;}E[MAXE],*V[MAXV];int tope=-1;void addedge(int x,int y){        E[++tope].np=y;        E[tope].next=V[x];        V[x]=&E[tope];}int uf[MAXN];int get_fa(int now){        return (now==uf[now])?now:(uf[now]=get_fa(uf[now]));}bool comb(int x,int y){        x=get_fa(x);        y=get_fa(y);        if (x==y)return false;        uf[x]=y;        return true;}int roof[MAXN],topr=-1;int state[MAXN];int ptr[MAXN];int v[MAXN];pair<qword,qword> dfs(int now,int f){        pair<qword,qword> ret,t;        Edge *ne;        ret=make_pair(v[now],0);        for (ne=V[now];ne;ne=ne->next)        {                if (ne->np==f)continue;                t=dfs(ne->np,now);                ret.second+=max(t.first,t.second);                ret.first+=t.second;        }        if (state[now])ret.first=-INFL;        return ret;}int main(){        int i,j,k;        int x,y,z;        qword ans=0;        scanf("%d",&n);        memset(ptr,-1,sizeof(ptr));        for (i=0;i<=n;i++)uf[i]=i;        for (i=0;i<n;i++)        {                scanf("%d%d",&v[i+1],&e[i][1]);                e[i][0]=i+1;                if (!comb(e[i][0],e[i][1]))                {                        roof[++topr]=e[i][0];                        e[i][2]=true;                        ptr[e[i][0]]=e[i][1];                }else                {                        addedge(e[i][0],e[i][1]);                        addedge(e[i][1],e[i][0]);                }        }        for (i=0;i<=topr;i++)        {                state[get_fa(roof[i])]=true;        }        for (i=1;i<=n;i++)        {                if (!state[get_fa(i)])                {                        state[get_fa(i)]=true;                        roof[++topr]=get_fa(i);                }        }        memset(state,0,sizeof(state));        pair<qword,qword> pr;        qword t;        for (i=0;i<=topr;i++)        {                if (ptr[roof[i]]==-1)                {                        pr=dfs(roof[i],roof[i]);                        ans+=max(pr.first,pr.second);                }else                {                        //state[roof[i]]=true;                        state[ptr[roof[i]]]=true;                        pr=dfs(roof[i],roof[i]);                        t=max(pr.first,pr.second);                        state[ptr[roof[i]]]=false;                        pr=dfs(roof[i],roof[j]);                        t=max(t,pr.second);                        ans+=t;                }        }        printf(LL"\n",ans);        return 0;}

 

 

bzoj 1040: [ZJOI2008]骑士 環套樹DP