很明显我们需要找出图中的环(肯定有环)
如上图,我们找的环为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;
}