题意

给定两个排列 $p$ 和 $d$,第 $1 \le i \le n$ 次将 $p_{d_i}$ 设为 0。

然后进行操作,一次操作定义为指定一个 $i$,将 $a_i = i$,问最少多少次操作能将它复原为一个排列(可能与原排列相同)。

思路

我一看,每次 $p_{i}$ 一定要做一次操作 $p_i=i$,那么 $p_{p_i}$ 也要操作,以此类推,直到 $p_k$ 等于 $k$。

那就好办了,每次讲 $p_i$ 和 $i$ 连在一起,分成几个联通块,每次的答案就是联通块的大小。

code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include<bits/stdc++.h>
#define int long long
using namespace std;
int T,n,p[100005],d[100005],f[100005],sz[100005],fg[100005],ans;
int fd(int x){
if(f[x]==x) return x;
return f[x]=fd(f[x]);
}
signed main(){
cin>>T;
while(T--){
cin>>n,ans=0;
for(int i=1;i<=n;i++) f[i]=i,sz[i]=1,fg[i]=0;
for(int i=1;i<=n;i++){
cin>>p[i];
if(fd(p[i])!=fd(i))
sz[fd(i)]+=sz[fd(p[i])],f[fd(p[i])]=fd(i);
}for(int i=1;i<=n;i++){
cin>>d[i];
if(!fg[fd(d[i])]) fg[fd(d[i])]=1,ans+=sz[fd(d[i])];
cout<<ans<<' ';
}cout<<'\n';
}
}