P2607 [ZJOI2008] 骑士

/*
每一个人只有一个厌恶的point 问选取若干个point 其权值max 可以有环
厌恶是一种偏序关系 u hate v -> v->u 即可
即可能是 基环树 或 树
基环树枚举 root 和fa[root] 不选
树 不影响
*/
/*
3
10 2
20 3
30 1

30
*/
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<string.h>
#include<queue>
#include<vector>
#include<bits/stdc++.h>
#define ll long long
#define ddd printf("-----------------------\n");
using namespace std;
const int maxn=1e6 +10;
const int mod=998244353;
const int inf=0x3f3f3f3f;

int n,val[maxn],fa[maxn],vis[maxn],root;
int head[maxn],to[maxn<<1],nxt[maxn<<1],tot;
ll f[maxn][2],ans;

void add(int a,int b){
    to[++tot]=b,nxt[tot]=head[a],head[a]=tot;
}

void dp(int u)
{
    vis[u]=1; f[u][0]=0,f[u][1]=val[u];
    for(int i=head[u];i;i=nxt[i])
    {
        int v=to[i];
        if(v!=root)
        {
            dp(v);
            f[u][0]+=max(f[v][0],f[v][1]);
            f[u][1]+=f[v][0];
        }
        else f[v][1]=-maxn;//如果存在环
    }
}
void find_circle(int u)
{
    vis[u]=1;root=u;
    while(vis[fa[root]]==0) root=fa[root],vis[root]=1;//if tree MLE
    dp(root);
    ll tmp=max(f[root][0],f[root][1]);
    root=fa[root];
    dp(root);
    ans+=max(tmp,max(f[root][0],f[root][1]));
}
int main()
{
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>val[i]>>fa[i];
        add(fa[i],i);
    }
    for(int i=1;i<=n;i++) if(fa[i]==0) fa[i]=i;
    
    for(int i=1;i<=n;i++) if(vis[i]==0) find_circle(i);
    
    cout<<ans<<'\n';
    
    return 0;
}

 

posted @ 2023-11-12 12:31  JMXZ  阅读(8)  评论(0)    收藏  举报