【题解】洛谷P2607【ZJOI2008】骑士

洛谷P2607:https://www.luogu.org/problemnew/show/P2607

一道毒瘤的环基树问题

第一次做环基树的题目

刚看题目的时候觉得不就是跟没有上司的舞会一样嘛

然后看着样例画了个图发现!!!

居然有环!!受到惊吓的蒟蒻

后来查了一下原来是叫环基树

思路

由于每个骑士有且仅有一个仇恨对象

So 整个图里有且只有一个环而且这个环必过根节点(为什么?)

把每个人的仇人设置为他的 父亲???

所以每个点的出度为1 那么根节点本来应该是0 但是为1 说明根节点在环中

我们只需要找出图中的环

遍历其中的点设为根节点

那么我们只需要在答案中加上取根节点不取其父亲和取父亲不取根节点中最大的

其他的按照:

  • 取此点的话 他的儿子都不能来
  • 不取此点 他的儿子要来不来都可以 显然取最大
  • f[i][0]不取此点 f[i][1]取此点

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 2000000
#define ll long long
using namespace std;
int n,cnt,root;
ll ans;
ll f[maxn][2],head[maxn],val[maxn],vis[maxn],fa[maxn];
struct Edge
{
    int next;
    int to;
}e[maxn];
void add(int u,int v)
{
    e[++cnt].to=v;
    e[cnt].next=head[u];
    head[u]=cnt;
}
void dp(int x)
{
    vis[x]=1;
    f[x][0]=0;
    f[x][1]=val[x];//初始化 
    for(int i=head[x];i;i=e[i].next)
    {
        int v=e[i].to;
        if(v!=root)//如果不是根节点 
        {
            dp(v);
            f[x][0]+=max(f[v][1],f[v][0]);//如果不取此点 儿子爱来不来 
            f[x][1]+=f[v][0]; //如果取此点 儿子都不能来 
        }
        else
        f[x][1]=-maxn;//如果是根节点 那么此点不能来设为最小值
    }
}
void find(int x)
{
    vis[x]=1;
    root=x;
    while(!vis[fa[root]])
    {
        root=fa[root];
        vis[root]=1;
    }//找环 
    dp(root);
    ll t=max(f[root][1],f[root][0]);//取最大值 
    vis[root]=1;
    root=fa[root];//重新定义根为根节点的其父亲 
    dp(root);
    ans+=max(t,max(f[root][1],f[root][0]));//取最大值 
    return;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int x;
        scanf("%lld%d",&val[i],&x);
        add(x,i);
        fa[i]=x;
    }
    for(int i=1;i<=n;i++)
        if(!vis[i])
            find(i);//找环 
    printf("%lld",ans);
} 
View Code

 

转载于:https://www.cnblogs.com/BrokenString/p/9520781.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值