旅行

【题目描述】

有N个城市,每个城市有一个机场,但是此机场的所有航班只飞往一个城市。每个城市有一个游览价值。

现询问,从第i个城市出发,游览价值之和最多为多少(一个城市只计算一次游览价值)。

【输入描述】

第一行输入一个正整数N;

第二行输入N个非负整数,表示每个城市的游览价值;

第三行输入N个正整数,表示第i个城市能够到达的城市。

【输出描述】

输出N行,每行包含一个非负整数,表示从第i个城市出发,游览价值之和最多为多少。

【样例输入】

8

5 4 3 2 1 1 1 1

2 3 1 1 2 7 6 8

【样例输出】

12

12

12

14

13

2

2

1

【数据范围及提示】

对于20%的数据,N ≤ 10;

对于40%的数据,N ≤ 1000;

对于100%的数据,N ≤ 200000。

源代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,Head=1,Tail=1,i[2000001],f[2000001],To[2000001],In[2000001],Q[2000001];
bool Vis1[2000001],Vis2[2000001];
int main()
{
    scanf("%d",&n);
    for (int a=1;a<=n;a++)
      scanf("%d",&i[a]);
    for (int a=1;a<=n;a++)
    {
        scanf("%d",&To[a]);
        In[To[a]]++; //入度。
    }
    for (int a=1;a<=n;a++)
      if (!In[a]) //入度为0。
      {
        Q[Tail++]=a;
        Vis1[a]=true;
      }
    while (Head!=Tail) //队列拓扑排序,队列细节需要注意。
    {
        if (!(--In[To[Q[Head]]]))
        {
            Q[Tail++]=To[Q[Head]];
            Vis1[To[Q[Head]]]=true;
        }
        Head++;
    }
    for (int a=1;a<=n;a++)
      if (!Vis1[a])
      {
        int Sum(0);
        for (int b=a;!Vis1[b];b=To[b]) //这是一个环。
        {
            Vis1[b]=true;
            Sum+=i[b];
        }
        for (int b=a;!Vis2[b];b=To[b]) //环内统一赋值。
        {
            f[b]=Sum;
            Vis2[b]=true;
        }
      }
    for (int a=Tail-1;a;a--) //注意循环顺序,因为越往下越靠底。
      f[Q[a]]=i[Q[a]]+f[To[Q[a]]];
    for (int a=1;a<=n;a++)
      printf("%d\n",f[a]);
    return 0;
}

/*
    本题数据范围很大,如果用常规的Tarjan做法会爆。
    仔细读题,可以发现,每条图形不过是一条链加上一个环,依照题目特性处理即可。
*/
posted @ 2016-10-17 21:06  前前前世。  阅读(183)  评论(0编辑  收藏  举报