[ZJOI2008]骑士

这个题,我们发现,他有两点比较坑人的地方。。。

1.这个图里面有多个联通块。。。

2.这不是一棵好看的树,它可能有环。。。

对于第一个,我们有一个bool数组存储,处理就好了。。。

那么对于第二个,我们可以发现,这个图中最多有一个环,那么我们把环断开。。。

对于每个端点做一次DP,这样结果就出来了。。。QAQ。。。

呆码:

#include<iostream>
#include<cstdio>
#define N 1000010
#define ll long long
using namespace std;

struct asd{
    int nxt;
    int to;
} a[N];

int head[N],fa[N],ft[N];
ll f[2][N],ans;
int num,n;
bool use[N];

inline void add(int x,int y)
{
    a[++num].nxt=head[x];
    a[num].to=y;
    head[x]=num;
}

inline void dp(int u,int father)
{
    use[u]=1;
    f[1][u]=ft[u];
    f[0][u]=0;
    for(int i=head[u];i;i=a[i].nxt)
    {
        int to=a[i].to;
        if(to==father) { f[1][to]=-999999999; continue; }
        dp(to,father);
        f[0][u]=max(f[0][u],max(f[0][u]+f[1][to],f[0][u]+f[0][to]));
        f[1][u]=max(f[1][u],f[1][u]+f[0][to]);
    }
}

inline void make(int x)
{
    while(!use[x])
    {
        use[x]=1;
        x=fa[x];
    }
    int y=fa[x];
    dp(x,x);
    ll cnt=max(f[0][x],f[1][x]);
    dp(y,y);
    ans+=max(cnt,max(f[0][y],f[1][y]));
}

int main()
{
    scanf("%d",&n);
    int x;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&ft[i]);
        scanf("%d",&x);
        add(x,i);
        fa[i]=x;
    }
    for(int i=1;i<=n;i++)
        if(!use[i]) make(i);
    printf("%lld
",ans);
}
代码
原文地址:https://www.cnblogs.com/zzzyc/p/9276276.html