题目地址:
https://www.acwing.com/problem/content/3582/
将 1 ∼ n 1∼n 1∼n按顺序排成一排,构成一个数列。数字 i i i刚好位于位置 i i i。再给定一个长度为 n n n的位置序列 p 1 , p 2 , … , p n p_1,p_2,…,p_n p1,p2,…,pn,它是 1 ∼ n 1∼n 1∼n的一种排列。接下来,我们会重复不断地对数列进行如下操作:重新排列数列中每个数的位置,将位于位置 i i i的数移动至位置 p i p_i pi。(如果 i = p i i=p_i i=pi则该数仍移动至位置 i i i)。每次操作开始时,所有数的移动同时进行,操作结束后,数列将变为一个新的 1 ∼ n 1∼n 1∼n的排列。例如,当 n = 6 n=6 n=6并且 p = [ 4 , 6 , 1 , 3 , 5 , 2 ] p=[4,6,1,3,5,2] p=[4,6,1,3,5,2]时,第一次操作后,数字 1 1 1将移动至位置 4 4 4,数字 2 2 2将移动至位置 6 6 6,以此类推;第二次操作后,数字 1 1 1将移动至位置 3 3 3,数字 2 2 2将移动至位置 2 2 2,以此类推。你的任务是确定从 1 1 1到 n n n的每个数字 i i i,经过多少次操作后,第一次重新回到位置 i。
例如,考虑 p=[5,1,2,4,3],数字 1 的移动轨迹如下:
第一次操作后,到达位置 5。
 第二次操作后,到达位置 3。
 第三次操作后,到达位置 2。
 第四次操作后,回到位置 1。
 所以,经过四次操作后,数字
    
     
      
       
        1
       
      
      
       1
      
     
    1第一次回到位置
    
     
      
       
        1
       
      
      
       1
      
     
    1。值得一提的是,数字
    
     
      
       
        4
       
      
      
       4
      
     
    4经过一次操作后就回到了位置
    
     
      
       
        4
       
      
      
       4
      
     
    4。
输入格式:
 第一行包含整数
    
     
      
       
        T
       
      
      
       T
      
     
    T,表示共有
    
     
      
       
        T
       
      
      
       T
      
     
    T组测试数据。每组数据第一行包含整数
    
     
      
       
        n
       
      
      
       n
      
     
    n。第二行包含
    
     
      
       
        n
       
      
      
       n
      
     
    n个整数
    
     
      
       
        
         p
        
        
         1
        
       
       
        ,
       
       
        …
       
       
        ,
       
       
        
         p
        
        
         n
        
       
      
      
       p_1,…,p_n
      
     
    p1,…,pn。
输出格式:
 每组数据输出一行结果,包含
    
     
      
       
        n
       
      
      
       n
      
     
    n个整数,其中第
    
     
      
       
        i
       
      
      
       i
      
     
    i个整数表示数字
    
     
      
       
        i
       
      
      
       i
      
     
    i第一次回到位置
    
     
      
       
        i
       
      
      
       i
      
     
    i所经过的操作次数。整数之间用单个空格隔开。
数据范围:
 对于
    
     
      
       
        30
       
      
      
       30%
      
     
    30的数据,
    
     
      
       
        1
       
       
        ≤
       
       
        T
       
       
        ≤
       
       
        10
       
      
      
       1≤T≤10
      
     
    1≤T≤10,
    
     
      
       
        1
       
       
        ≤
       
       
        n
       
       
        ≤
       
       
        10
       
      
      
       1≤n≤10
      
     
    1≤n≤10。
 对于
    
     
      
       
        100
       
      
      
       100%
      
     
    100的数据,
    
     
      
       
        1
       
       
        ≤
       
       
        T
       
       
        ≤
       
       
        1000
       
      
      
       1≤T≤1000
      
     
    1≤T≤1000,
    
     
      
       
        1
       
       
        ≤
       
       
        n
       
       
        ≤
       
       
        2
       
       
        ×
       
       
        1
       
       
        
         0
        
        
         5
        
       
      
      
       1≤n≤2×10^5
      
     
    1≤n≤2×105,
    
     
      
       
        1
       
       
        ≤
       
       
        
         p
        
        
         i
        
       
       
        ≤
       
       
        n
       
      
      
       1≤p_i≤n
      
     
    1≤pi≤n。
 保证
    
     
      
       
        
         p
        
        
         1
        
       
       
        ∼
       
       
        
         p
        
        
         n
        
       
      
      
       p_1∼p_n
      
     
    p1∼pn是
    
     
      
       
        1
       
       
        ∼
       
       
        n
       
      
      
       1∼n
      
     
    1∼n的一种排列。
 保证
    
     
      
       
        ∑
       
       
        n
       
       
        ≤
       
       
        2
       
       
        ×
       
       
        1
       
       
        
         0
        
        
         5
        
       
      
      
       ∑n≤2×10^5
      
     
    ∑n≤2×105(一个输入中的
    
     
      
       
        T
       
      
      
       T
      
     
    T个
    
     
      
       
        n
       
      
      
       n
      
     
    n相加之和不超过
    
     
      
       
        2
       
       
        ×
       
       
        1
       
       
        
         0
        
        
         5
        
       
      
      
       2×10^5
      
     
    2×105)。
根据抽象代数里的相关定理,每个置换都可以分解为若干不相交的轮换的乘积,那么每个数变换多少次回到自己相当于问其所在的轮换的元素个数,可以用并查集来做。代码如下:
#include <iostream>
using namespace std;
const int N = 2e5 + 10;
int n;
int p[N], sz[N];
int find(int x) {
  if (x != p[x]) p[x] = find(p[x]);
  return p[x];
}
int main() {
  int T;
  scanf("%d", &T);
  while (T--) {
    for (int i = 1; i <= n; i++) {
      p[i] = i;
      sz[i] = 1;
    }
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
      int x;
      scanf("%d", &x);
      int pi = find(i), px = find(x);
      if (pi != px) {
        p[pi] = px;
        sz[px] += sz[pi];
      }
    }
    
    for (int i = 1; i <= n; i++) printf("%d ", sz[find(i)]);
    puts("");
  }
}
每组数据时间复杂度 O ( n log  ∗ n ) O(n\log^*n) O(nlog∗n),空间 O ( n ) O(n) O(n)。










