简单来说就给一个排列,每一个元素要满足其中一个:
- pi=i
- p[pi]=i
其实我也没想到并查集和图;贪心然后WA掉惹
将每一个节点和他的pi相连,会得到诺干的单向图,然后每一块图只需修改便可让其成为两两一对的双向图(满足第二条),如果n为奇数,会独立出一个节点,这个节点在其他节点交换完成后一定满足第一条:因为一个图里的值如果是[a,b]那么它里面的元素也是在排列的[a,b]个中,
待其他交换完,剩下的那个只能留着pi = i的这个坑里面
import java.util.Map;
import java.util.Scanner;
import java.util.TreeMap;
public class CFR981E {
int[] father;
static int n;
public void init(){
father = new int[n];
for(int i = 0; i < n; i++){
father[i] = i;
}
}
public int find(int u){
if(u == father[u]){
return u;
}else
return father[u] = find(father[u]);
}
public void join(int u,int v){
u = find(u);
v = find(v);
if(u == v)
return;
father[u] = v;
}
public static void main(String[] args) {
CFR981E uf = new CFR981E();
int t;
Scanner sc = new Scanner(System.in);
t = sc.nextInt();
while(t-- > 0){
n = sc.nextInt();
uf.init();
int[] nums = new int[n];
for(int i = 0; i < n; i++){
nums[i] = sc.nextInt() - 1;
}
for(int i = 0; i < n; i++){
uf.join(nums[i],nums[nums[i]]);
}
Map<Integer, Integer> map = new TreeMap<>();
for(int i = 0; i < n; i++){
int cur = uf.find(nums[i]);
map.put(cur, map.getOrDefault(cur, 0) + 1);
}
int ans = 0;
for(Integer val : map.values()){
ans += (val-1) / 2;
}
System.out.println(ans);
}
}
}
凭什么和C一样的难度