library/util/Permutation.hpp
Depends on
Code
#pragma once
#define REP_(i, n) for (int i = 0; i < (n); i++)
struct Perm {
using vi = std::vector<int>;
// (v[i],i) で座圧
template <typename T> static vi make_perm(const std::vector<T> &v) {
vi w = v;
std::ranges::sort(w);
std::map<T, int> mp;
REP_(i, v.size()) if (!i or w[i - 1] != w[i]) mp[w[i]] = i;
REP_(i, v.size()) w[i] = mp[v[i]]++;
return w;
}
// r[p[i]]=i;
static vi rev(const vi &p) {
assert(is_permutation(p));
auto res = p;
REP_(i, p.size()) res[p[i]] = i;
return res;
}
// r[i] = p[q[i]]
static vi composite(const vi &p, const vi &q) {
assert(p.size() == q.size());
assert(is_permutation(p));
assert(is_permutation(q));
auto res = p;
REP_(i, p.size()) res[i] = p[q[i]];
return res;
}
static std::vector<vi> divide_cycle(const vi &p) {
assert(is_permutation(p));
int n = p.size();
std::vector<bool> used(n, false);
std::vector<vi> res;
for (int x : p) {
if (used[x])
continue;
used[x] = true;
res.emplace_back(vi{x});
int now = p[x];
while (now != x) {
assert(!used[now]);
used[now] = true;
res.back().push_back(now);
now = p[now];
}
}
return res;
}
static bool is_permutation(const vi &p) {
int n = p.size();
std::vector<bool> used(n, false);
for (int x : p) {
if (used[x])
return false;
used[x] = true;
}
return true;
}
private:
static void rearrange(const vi &p) {}
template <typename T>
static void execute_rearrange(const vi &p, std::vector<T> &v) {
assert(p.size() == v.size());
auto w = v;
REP_(i, p.size()) w[i] = v[p[i]];
std::swap(v, w);
}
public:
// v を (p[i],v[i]) での昇順にする
template <typename Head, typename... Tail>
static void rearrange(const vi &p, Head &v, Tail &...tail) {
execute_rearrange(p, v);
rearrange(p, tail...);
}
};
#undef REP_
#line 2 "library/util/Permutation.hpp"
#define REP_(i, n) for (int i = 0; i < (n); i++)
struct Perm {
using vi = std::vector<int>;
// (v[i],i) で座圧
template <typename T> static vi make_perm(const std::vector<T> &v) {
vi w = v;
std::ranges::sort(w);
std::map<T, int> mp;
REP_(i, v.size()) if (!i or w[i - 1] != w[i]) mp[w[i]] = i;
REP_(i, v.size()) w[i] = mp[v[i]]++;
return w;
}
// r[p[i]]=i;
static vi rev(const vi &p) {
assert(is_permutation(p));
auto res = p;
REP_(i, p.size()) res[p[i]] = i;
return res;
}
// r[i] = p[q[i]]
static vi composite(const vi &p, const vi &q) {
assert(p.size() == q.size());
assert(is_permutation(p));
assert(is_permutation(q));
auto res = p;
REP_(i, p.size()) res[i] = p[q[i]];
return res;
}
static std::vector<vi> divide_cycle(const vi &p) {
assert(is_permutation(p));
int n = p.size();
std::vector<bool> used(n, false);
std::vector<vi> res;
for (int x : p) {
if (used[x])
continue;
used[x] = true;
res.emplace_back(vi{x});
int now = p[x];
while (now != x) {
assert(!used[now]);
used[now] = true;
res.back().push_back(now);
now = p[now];
}
}
return res;
}
static bool is_permutation(const vi &p) {
int n = p.size();
std::vector<bool> used(n, false);
for (int x : p) {
if (used[x])
return false;
used[x] = true;
}
return true;
}
private:
static void rearrange(const vi &p) {}
template <typename T>
static void execute_rearrange(const vi &p, std::vector<T> &v) {
assert(p.size() == v.size());
auto w = v;
REP_(i, p.size()) w[i] = v[p[i]];
std::swap(v, w);
}
public:
// v を (p[i],v[i]) での昇順にする
template <typename Head, typename... Tail>
static void rearrange(const vi &p, Head &v, Tail &...tail) {
execute_rearrange(p, v);
rearrange(p, tail...);
}
};
#undef REP_
Back to top page