题意:
思路:
先从排好序的数组考虑:1,2,3,4,5,...n,如果交换相邻元素,必然使得逆序对数+1。
考虑先将乱序数组变成顺序数组,最后交换任意一对相邻元素即可。
将所有的i与\(p_{i}\)连边,最后形成若干个环,交换次数其实就是边数,也即点数-环数。并查集维护。
注意特殊情况:如果任意一对相邻元素处于同一个环中,可以不需要先变成顺序,再交换相邻元素,可以直接一步到位使得逆序对数为1。
code:
#include <bits/stdc++.h>
#include<bits/extc++.h>
using namespace __gnu_pbds;
using namespace std;
using i64 = long long;
using u64 = unsigned long long;
using PII = pair<i64, i64>;
const int inf = 0x3f3f3f3f;
const i64 INF = 0x3f3f3f3f3f3f3f3f;
#define Z cout << "\n"
#define lb lower_bound
#define ub upper_bound
#define D(x) cerr << #x << ": " << (x) << "\n"
#define DV(v) cerr<<#v<<": ";for(int i=0;i<(v).size();i++)cerr<<((v)[i])<<",";cerr<<"\n"
#if 0
#define int i64
#endif
struct DSU {vector<int> fa, siz;DSU() {}DSU(int n) { init(n); }void init(int n) { fa.resize(n); iota(fa.begin(), fa.end(), 0); siz.assign(n, 1); }int find(int x) { while (x != fa[x]) { x = fa[x] = fa[fa[x]]; }return x; }bool same(int x, int y) { return find(x) == find(y); }bool merge(int x, int y) { x = find(x); y = find(y); if (x == y) { return false; }siz[x] += siz[y]; fa[y] = x; return true; }int size(int x) { return siz[find(x)]; }
};
signed main() {ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);int t;cin >> t;while (t--) {int n;cin >> n;DSU dsu(n + 1);vector<int>a(n + 5);for (int i = 1; i <= n; i++)cin >> a[i], dsu.merge(i, a[i]);int x = 0;for (int i = 1; i <= n; i++) {if (dsu.find(i) == i)x++;}int ans = n - x;bool ok = 0;for (int i = 1; i <= n - 1; i++) {if (dsu.same(i, i + 1))ok = 1;}if (ok)ans--; else ans++;cout << ans << "\n";}return 0;
}