传球接力

这里写图片描述
很明显我们需要找出图中的环(肯定有环)
这里写图片描述
如上图,我们找的环为1->4->3->2->1
环的总长度确定了,但是起点并没有确定,我们有两种选择
一个是6->2->1->4->3(总长度16)
另一个为5->4->3->2->1(总长度25)
很明显是第二种长,我们该如何得出答案
令sum为环的长度,但是环的长度中有一条是加入不进去的,那就是起点切入环的点指向这个点的环上边
我们令fi为i的叶子节点的最长的链的长度
我们枚举指向切入点的点,把这边去掉,然后加入f[切入点],即可算出长度,循环环中节点的个数次
取max即可
第一次使用tarjan求环,栈溢出(80)
由于在这道体中每个点只会指向一个点,使用一个for即可找到所有的环
复杂度:O(n)。
注意答案开long long

#include <cstdio>
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
const int max1=510000;
int r[max1];
int a[max1];
int max_date[max1];
int n,d[max1];
int cyclelen;
int cycle[max1];
int no_r[max1],cnt;
bool vis[max1];
long long dis_sum=0;
long long ans=0;
int pre[max1];
void js()
{
    for(int i=1;i<=cyclelen;i++)
     ans=max(ans,(long long)dis_sum-d[cycle[i]]+max_date[a[cycle[i]]]);
}
int main()
{
    freopen("pass.in","r",stdin);
    freopen("pass.out","w",stdout);
    scanf("%d",&n);

    for(int i=1;i<=n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        a[i]=x; 
        d[i]=y;
        r[x]++;
    }
    int l=0,rt=0;
    for(int i=1;i<=n;i++)
     if(r[i]==0) no_r[++rt]=i;
    while (l<rt)//求f数组
    {
        int k=no_r[++l];
        if(max_date[k]+d[k]>max_date[a[k]]) max_date[a[k]]=max_date[k]+d[k];
        if(--r[a[k]]==0) no_r[++rt]=a[k];
    } 

    for (int i=1; i<=n; ++i)
    if (r[i]>0&&!vis[i])
    {
        int k=i;
        cyclelen=0;
        dis_sum=0;
        do
        {
            vis[k]=true;
            cycle[++cyclelen]=k;
            dis_sum+=d[k];
            k=a[k];
        }while(k!=i);
        js();

    }

    printf("%lld",ans); 
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值