結果
問題 | No.2289 順列ソート |
ユーザー |
![]() |
提出日時 | 2023-05-05 22:42:55 |
言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 2 ms / 2,000 ms |
コード長 | 6,408 bytes |
コンパイル時間 | 1,339 ms |
コンパイル使用メモリ | 123,192 KB |
最終ジャッジ日時 | 2025-02-12 19:03:14 |
ジャッジサーバーID (参考情報) |
judge1 / judge5 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 3 |
other | AC * 21 |
ソースコード
//#pragma GCC target("avx2")//#pragma GCC optimize("O3")//#pragma GCC optimize("unroll-loops")#include <iostream>#include <iomanip>#include <algorithm>#include <vector>#include <string>#include <set>#include <map>#include <cassert>#include <cmath>#include <tuple>#include <queue>#include <bitset>using namespace std;using lg = long long;#define TEST clog << "TEST" << endl#define IINF 2147483647#define LLINF 9223372036854775807LL#define AMARI 998244353#define TEMOTO ((sizeof(long double) == 16) ? false : true)#define TIME_LIMIT 1980 * (TEMOTO ? 1 : 1000)#define el '\n'#define El '\n'//RMQとRSQをまとめたセグ木(遅延ではない)//最小値の取得と区間和の取得ができる 関数名さえ見てればrmqとかrsqとかあんま考えなくても行けるはず//最小値の取得をする場合について、syokica()内の初期値の設定だけIINFになっているところを、その型で取り得る最大値に書き換えた方が安全template<typename T>class ococo_segtree {public:int n;T tmax;//range sum queryvector<T> rsq;//range minimum queryvector<T> rmq;ococo_segtree(int N = 0, T t = IINF) {syokica(N, t);}//配列の初期化 O(N)void syokica(int a, T t) {n = 1;tmax = t;while (n < a)n *= 2;rsq.resize(2 * n - 1);rmq.resize(2 * n - 1);for (int i = 0; i < 2 * n - 1; i++) {rsq[i] = 0;//型Tのmaxの値を入れたいrmq[i] = tmax;}}//a[i]をxにする O(logN)void update_num(int i, T x) {i += (n - 1);rmq[i] = x;T dif = x - rsq[i];rsq[i] += dif;while (i) {i = (i - 1) / 2;rmq[i] = min(rmq[i * 2 + 1], rmq[i * 2 + 2]);rsq[i] += dif;}}//a[i]にxを加える O(logN)void add_num(int i, T x) {i += (n - 1);rsq[i] += x;rmq[i] = min(rmq[i], x);while (i) {i = (i - 1) / 2;rsq[i] += x;rmq[i] = min(rmq[i * 2 + 1], rmq[i * 2 + 2]);}}T get_sum2(int a, int b, int k, int l, int r) {//cout << k << endl;if (a <= l && r <= b)return rsq[k];else if (r <= a || b <= l)return 0;else {T temp = (get_sum2(a, b, k * 2 + 1, l, (l + r) / 2) + get_sum2(a, b, k * 2 + 2, (l + r) / 2, r));return temp;}}//[l,r)の和の取得 O(logN)T get_sum(int l, int r) {return get_sum2(l, r, 0, 0, n);}T get_minimum2(int a, int b, int k, int l, int r) {if (a <= l && r <= b)return rmq[k];else if (r <= a || b <= l)return tmax;else return min(get_minimum2(a, b, k * 2 + 1, l, (l + r) / 2), get_minimum2(a, b, k * 2 + 2, (l + r) / 2, r));}//[l,r)の最小値の取得 O(logN)T get_minimum(int l, int r) {return get_minimum2(l, r, 0, 0, n);}};class ococo_unionfind {//できること//点の挿入//その点の根を求める関数//辺の挿入//連結判定//島が何個あるかの出力//それぞれの島について、何個の点があるかの出力public:ococo_unionfind(int n = 0) {for (int i = 0; i < n; i++)vinsert();}int simakosuu = 0;//g[i] = {その点の一個上の点,その点のrank}//その点のrank:その点の下に何個点があるか(上に何個あるかに変えた方がいいかも?)vector<pair<int, int>> g;//rs[i] = その点が含まれている連結成分に何個の点があるか//その連結成分の根について聞かないと返さないvector<int> rs;//点の挿入 O(1)void vinsert(void) {g.emplace_back(g.size(), 1);simakosuu++;rs.push_back(1);}//ある点の根を求める関数 O(α(N))int ne(int a) {if (g[a].first == a)return a;else {return g[a].first = ne(g[a].first);}}//辺の挿入 O(logN)void einsert(int a, int b) {if (a != b) {int a1 = ne(a), a2 = ne(b);if (a1 != a2) {simakosuu--;int rs12sum = rs[a1] + rs[a2];rs[a1] = rs12sum;rs[a2] = rs12sum;if (g[a1].second < g[a2].second) {g[a1].first = a2;g[a2].second = max(g[a1].second + 1, g[a2].second);}else {g[a2].first = a1;g[a1].second = max(g[a2].second + 1, g[a1].second);}}}}//2つのノードが繋がっているか判定する関数 O(α(N))bool renketucheck(int a, int b) {if (ne(a) == ne(b))return true;else return false;}//何個の島に分かれているか出力する関数 O(1)int islandnum(void) {return simakosuu;}//ある点について、その点が含まれている連結成分が何個の点を持つか返す関数 O(α(N))int islandsize(int a) {return rs[ne(a)];}};#define MULTI_TEST_CASE falsevoid solve(void) {int n;cin >> n;vector<int> a(n);ococo_unionfind ouf(n);for (int i = 0; i < n; i++) {cin >> a[i];a[i]--;ouf.einsert(a[i], i);}vector<vector<int>> v(n);for (int i = 0; i < n; i++) {v[ouf.ne(i)].push_back(a[i]);}lg ans = 0;for (int i = 0; i < n; i++) {if (v[i].size() <= 1)continue;//for (int j = 0; j < v[i].size(); j++)clog << v[i][j] << ' ';// clog << el;set<int> s;for (int j = 0; j < v[i].size(); j++)s.insert(v[i][j]);map<int, int> mp;int cnt = 0;for (set<int>::iterator it = s.begin(); it != s.end(); it++) {mp[*it] = cnt;cnt++;}//ans += max(mp[v[i][0]], (int)v[i].size() - mp[v[i][0]]);ans += v[i].size() - 1;}cout << ans << el;return;}void calc(void) {return;}int main(void) {cin.tie(nullptr);ios::sync_with_stdio(false);int t = 1;if (MULTI_TEST_CASE)cin >> t;while (t--) {solve();}calc();return 0;}