【NOIP2011模拟9.17】旅行

本文介绍了一个旅行问题的解决方法,该问题涉及多个城市的游览价值计算。通过拓扑排序找到环内的城市,进而计算从任意城市出发能获得的最大游览价值总和。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

X先生来到了一个奇怪的国家旅行。这个国家有N个城市,每个城市均有且仅有一个机场,但是这机场所有航班只飞往一个城市。每个城市有一个游览价值,第i个城市的游览价值为A[i]。
现在他想知道,从第i个城市出发,并只坐飞机飞往下一个城市,游览价值之和最多是多少(一个城市游览多次只计算1次游览价值)

Input

输入文件travel.in的第1行为一个正整数N。
第2行有N个非负整数A[i],表示了每个城市的游览价值。
第3行有N个正整数F[i],表示第i个城市的航班飞往的城市为F[i],可能出现F[i] = i的情况。

Output

输出文件travel.out包括N行,第i行包含一个非负整数,表示从第i个城市出发游览价值之和的最大值为多少。

Sample Input

8

5 4 3 2 1 1 1 1

2 3 1 1 2 7 6 8

Sample Output

12

12

12

14

13

2

2

1

Data Constraint

Hint

对于20%的数据,N≤10;
对于40%的数据,N≤1000;
对于100%的数据,N≤200000,A[i]≤10000,F[i]≤N。

分析:我们先进行一次拓扑排序。然后对于每个入度大于0的点,一定在环中。然后我们对每个环都进行计算,同一环中的数的价值相同。然后从环逆向枚举即可。

代码:

const
 maxn=300001;
var
 b,f,num,ru:array [0..maxn] of longint;
 flag,h:array [0..maxn] of boolean;
 i,j,n,x,t:longint;
procedure init;
 var i:longint;
begin
 readln(n);
 for i:=1 to n do
  read(f[i]);
 for i:=1 to n do
 begin
  read(b[i]);
  inc(ru[b[i]]);
 end;
end;

procedure tpsort;
 var i,l,head,tail,x,j:longint;
     tp:array [0..200001] of longint;
begin
head:=0; tail:=0;
 for i:=1 to n do
  if ru[i]=0 then
   begin
    inc(tail);
    tp[tail]:=i;
   end;
 repeat
  if tail=0 then break; 
  inc(head);
  dec(ru[b[tp[head]]]);
 if ru[b[tp[head]]]=0 then
  begin
   inc(tail);
   tp[tail]:=b[tp[head]];
  end;
 until head=tail;
 x:=0;
 for i:=1 to n do
  begin
   if (ru[i]<>0) and not h[i] then
    begin
     j:=b[i];
     h[i]:=true;
     while j<>i do
      begin
       h[j]:=true;
       num[j]:=i;
       f[i]:=f[i]+f[j];
       j:=b[j];
      end;
    end;
  end;

end;
procedure dfs(x:longint);
var t:longint;
 begin
  if h[b[x]]=false then
   dfs(b[x]);
  if num[b[x]]=0 then f[x]:=f[x]+f[b[x]]
                 else f[x]:=f[x]+f[num[b[x]]];
  h[x]:=true;
 end;

begin
 init;
 fillchar(h,sizeof(h),false);
 tpsort;
 for i:=1 to n do
  begin
   if h[i]=false then dfs(i);
   if num[i]=0 then writeln(f[i])
               else writeln(f[num[i]]);
  end;
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值