F. Selling a Menagerie

F. Selling a Menagerie

You are the owner of a menagerie consisting of n animals numbered from 1 to n. However, maintaining the menagerie is quite expensive, so you have decided to sell it!

It is known that each animal is afraid of exactly one other animal. More precisely, animal i is afraid of animal ai (aii). Also, the cost of each animal is known, for animal i it is equal to ci.

You will sell all your animals in some fixed order. Formally, you will need to choose some permutation p1,p2,,pn, and sell animal p1 first, then animal p2, and so on, selling animal pn last.

When you sell animal i, there are two possible outcomes:

  • If animal ai was sold before animal i, you receive ci money for selling animal i.
  • If animal ai was not sold before animal i, you receive 2ci money for selling animal i. (Surprisingly, animals that are currently afraid are more valuable).

Your task is to choose the order of selling the animals in order to maximize the total profit.

For example, if a=[3,4,4,1,3], c=[3,4,5,6,7], and the permutation you choose is [4,2,5,1,3], then:

  • The first animal to be sold is animal 4. Animal a4=1 was not sold before, so you receive 2c4=12 money for selling it.
  • The second animal to be sold is animal 2. Animal a2=4 was sold before, so you receive c2=4 money for selling it.
  • The third animal to be sold is animal 5. Animal a5=3 was not sold before, so you receive 2c5=14 money for selling it.
  • The fourth animal to be sold is animal 1. Animal a1=3 was not sold before, so you receive 2c1=6 money for selling it.
  • The fifth animal to be sold is animal 3. Animal a3=4 was sold before, so you receive c3=5 money for selling it.

Your total profit, with this choice of permutation, is 12+4+14+6+5=41. Note that 41 is not the maximum possible profit in this example.

A permutation of length n is an array consisting of n distinct integers from 1 to n in any order. For example, [2,3,1,5,4] is a permutation, but [1,2,2] is not a permutation (2 appears twice in the array) and [1,3,4] is also not a permutation (n=3, but 4 is present in the array).

Input

The first line of the input contains an integer t (1t104) — the number of test cases.

Then follow the descriptions of the test cases.

The first line of each test case description contains an integer n (2n105) — the number of animals.

The second line of the test case description contains n integers a1,a2,,an (1ain, aii) — ai means the index of the animal that animal i is afraid of.

The third line of the test case description contains n integers c1,c2,,cn (1ci109) — the costs of the animals.

It is guaranteed that the sum of n over all test cases does not exceed 105.

Output

Output t lines, each containing the answer to the corresponding test case. The answer should be n integers — the permutation p1,p2,,pn, indicating in which order to sell the animals in order to maximize the profit. If there are multiple possible answers, you can output any of them.

Example

input

复制代码
8
3
2 3 2
6 6 1
8
2 1 4 3 6 5 8 7
1 2 1 2 2 1 2 1
5
2 1 1 1 1
9 8 1 1 1
2
2 1
1000000000 999999999
7
2 3 2 6 4 4 3
1 2 3 4 5 6 7
5
3 4 4 1 3
3 4 5 6 7
3
2 1 1
1 2 2
4
2 1 4 1
1 1 1 1
复制代码

output

1 2 3
2 4 5 1 6 3 7 8
3 4 5 1 2
1 2
7 5 1 3 2 6 4
5 3 2 4 1
3 2 1
3 4 1 2

 

解题思路

  比赛最后几分钟做了出来,主要卡在了处理挂在环上的链,代码写得又长又臭。

  如果从iai连一条边iai,那么可以发现得到的图是一个基环树,这是因为每个节点都恰好有一个出度。分别考虑基环树中的环以及挂在环上的树。对于挂在环上的树,也就是不在环中的点,我们总是可以通过拓扑排序找出来,那么剩余的点自然就是环上的点了,这样就可以把环以及挂在环上的树分离开来。

  对于某个节点u,如果存在害怕u的动物v,即u的入度不为0,那么很明显先卖v再卖u所得到的收益比先卖u再卖v要多(至少不会变差)。因此继续顺着找到害怕v的动物,以此类推直到找到某个点x,不存在害怕x的动物,即x的入度为0,那么就先售卖x,这样做肯定是最优的。

  为此先对不在环中的点进行售卖,可以发现每个点都能获得两倍的收益。只需按照拓扑的顺序进行售卖即可,这样就可以保证每次卖掉的点的入度均为0。然后就是环上的点,可以发现无论按什么顺序卖掉,都至少有一个点不能获得两倍收益(因为必然存在只剩一个点的情况)。为了能得到最大收益,假设环中cx最小,那么我们按照axaaxx的顺序进行售卖,那么除了x外,其余的点都能获得两倍收益。

  要注意得到的图不一定是连通的,因此要分别处理每个基环树。

  AC代码如下,时间复杂度为O(n)

复制代码
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 typedef long long LL;
 5 
 6 const int N = 1e5 + 10;
 7 
 8 int a[N], c[N];
 9 int deg[N];
10 bool vis[N];
11 int q[N], hh, tt;
12 
13 void solve() {
14     int n;
15     scanf("%d", &n);
16     memset(deg, 0, n + 10 << 2);
17     memset(vis, 0, n + 10);
18     for (int i = 1; i <= n; i++) {
19         scanf("%d", a + i);
20         deg[a[i]]++;
21     }
22     for (int i = 1; i <= n; i++) {
23         scanf("%d", c + i);
24     }
25     hh = 0, tt = -1;
26     for (int i = 1; i <= n; i++) {
27         if (!deg[i]) q[++tt] = i;
28     }
29     while (hh <= tt) {    // 先把不在环上的点找出来 
30         int t = q[hh++];
31         vis[t] = true;    // 不在环上的点被标记 
32         printf("%d ", t);    // t的入度为0,因此卖掉 
33         if (--deg[a[t]] == 0) q[++tt] = a[t];
34     }
35     for (int i = 1; i <= n; i++) {
36         if (vis[i]) continue;    // 没有被标记的点一定是环上的点 
37         int t = i;
38         vector<int> p;
39         while (!vis[t]) {    // 把环上的点都找出来 
40             vis[t] = true;
41             p.push_back(t);
42             t = a[t];
43         }
44         int k = 0;    // 找到收益最小的点 
45         for (int i = 0; i < p.size(); i++) {
46             if (c[p[i]] < c[p[k]]) k = i;
47         }
48         for (int i = 0; i < p.size(); i++) {    // 收益最小的点最后卖掉 
49             if (++k == p.size()) k = 0;
50             printf("%d ", p[k]);
51         }
52     }
53     printf("\n");
54 }
55 
56 int main() {
57     int t;
58     scanf("%d", &t);
59     while (t--) {
60         solve();
61     }
62     
63     return 0;
64 }
复制代码

 

参考资料

  Codeforces Round 895 (Div. 3) Editorial:https://codeforces.com/blog/entry/120165

posted @   onlyblues  阅读(72)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
Web Analytics
点击右上角即可分享
微信分享提示