【题目描述】
有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 ",f[a]); return 0; } /* 本题数据范围很大,如果用常规的Tarjan做法会爆。 仔细读题,可以发现,每条图形不过是一条链加上一个环,依照题目特性处理即可。 */