洛谷P2607 [ZJOI2008] 骑士 题解

洛谷P2607 [ZJOI2008] 骑士 题解

题目链接:P2607 [ZJOI2008] 骑士

题意

Z 国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英。他们劫富济贫,惩恶扬善,受到社会各界的赞扬。

最近发生了一件可怕的事情,邪恶的 Y 国发动了一场针对 Z 国的侵略战争。战火绵延五百里,在和平环境中安逸了数百年的 Z 国又怎能抵挡的住 Y 国的军队。于是人们把所有的希望都寄托在了骑士团的身上,就像期待有一个真龙天子的降生,带领正义打败邪恶。

骑士团是肯定具有打败邪恶势力的能力的,但是骑士们互相之间往往有一些矛盾。每个骑士都有且仅有一个自己最厌恶的骑士(当然不是他自己),他是绝对不会与自己最厌恶的人一同出征的。

战火绵延,人民生灵涂炭,组织起一个骑士军团加入战斗刻不容缓!国王交给了你一个艰巨的任务,从所有的骑士中选出一个骑士军团,使得军团内没有矛盾的两人(不存在一个骑士与他最痛恨的人一同被选入骑士军团的情况),并且,使得这支骑士军团最具有战斗力。

为了描述战斗力,我们将骑士按照 1 1 1 n n n 编号,给每名骑士一个战斗力的估计,一个军团的战斗力为所有骑士的战斗力总和。

对于 100 % 100\% 100% 的测试数据,满足 1 ≤ n ≤ 1 0 6 1\le n \le 10^6 1n106,每名骑士的战斗力都是不大于 1 0 6 10^6 106 的正整数。

经典的基环树dp题

因为结点只有一个出边,所以一定是基环树

值得注意的是,这道题给出的是一个基环树森林

就多跑几遍就好了,时间复杂度 O ( n ) O(n) O(n)

这里是并查集判环写法,常数还算可以接受

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
namespace FastIO
{
    #define gc() readchar()
    #define pc(a) putchar(a)
    #define SIZ (int)(1e6+15)
    char buf1[SIZ],*p1,*p2;
    char readchar()
    {
        if(p1==p2)p1=buf1,p2=buf1+fread(buf1,1,SIZ,stdin);
        return p1==p2?EOF:*p1++;
    }
    template<typename T>void read(T &k)
    {
        char ch=gc();T x=0,f=1;
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
        while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
        k=x*f;
    }
    template<typename T>void write(T k)
    {
        if(k<0){k=-k;pc('-');}
        static T stk[66];T top=0;
        do{stk[top++]=k%10,k/=10;}while(k);
        while(top){pc(stk[--top]+'0');}
    }
}using namespace FastIO;
#define N (int)(1e6+15)

struct Edge
{
    int u,v,next;
}e[N<<1];
vector< pair<int,int> >vec;
int n,res,pos=1,head[N],val[N],f[N],dp[N][2];
void addEdge(int u,int v)
{
    e[++pos]={u,v,head[u]};
    head[u]=pos;
}
void init(){for(int i=1; i<=n; i++)f[i]=i;}
int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
void merge(int u,int v){f[find(u)]=find(v);}
void dfs(int u,int fa)
{
    dp[u][0]=0;dp[u][1]=val[u];
    for(int i=head[u]; i; i=e[i].next)
    {
        int v=e[i].v;
        if(v==fa)continue;
        dfs(v,u);
        dp[u][1]+=dp[v][0];
        dp[u][0]+=max(dp[v][0],dp[v][1]);
    }
}
signed main()
{
    read(n);
    init();for(int i=1,v; i<=n; i++)
    {
        read(val[i]);read(v);
        if(find(i)==find(v))
        {
            vec.push_back({i,v});
            continue;
        }
        addEdge(i,v);addEdge(v,i);merge(i,v);
    }
    int res=0,s,t,tmp;
    for(auto i : vec)
    {
        s=i.first,t=i.second;
        dfs(s,s);tmp=dp[s][0];
        dfs(t,t);tmp=max(tmp,dp[t][0]);
        res+=tmp;
    }
    printf("%lld\n",res);
    return 0;
}

转载请说明出处

你可能感兴趣的:(OI,算法,数据结构)