Problem:
Permutation Period
You have a permutation $p$ of $N$ integers. Initially $p_i = i$ holds for $1 \leq i \leq N$. For each $j$ ($1 \leq j \leq N$), let's denote $p_{j}^0 = j$ and $p_{j}^k = p_{p_j}^{k-1}$ for any $k\geq 1$. The
period
of $p$ is defined as the minimum positive integer $k$ which satisfies $p_{j}^k = j$ for every $j$ ($1 \leq j \leq N$).
You are given $Q$ queries. The $i$-th query is characterized by two distinct indices $x_i$ and $y_i$. For each query, swap $p_{x_i}$ and $p_{y_i}$ and then calculate the period of updated $p$ modulo $10^9 + 7$ in the given order.
It can be proved that the period of $p$ always exists.
Input
The input consists of a single test case of the following format.
$N$ $Q$
$x_1$ $y_1$
...
$x_Q$ $y_Q$
The first line consists of two integers $N$ and $Q$ ($2 \leq N \leq 10^5, 1 \leq Q \leq 10^5$). The ($i+1$)-th line consists of two integers $x_i$ and $y_i$ ($1 \leq x_i, y_i \leq N, x_i \ne y_i$).
Output
Print the answer in one line for each query.
Sample Input 1
5 4
2 5
2 4
1 3
1 2
Output for Sample Input 1
2
3
6
5
$p$ changes as follows: $[1,2,3,4,5] \rightarrow [1,5,3,4,2] \rightarrow [1,4,3,5,2] \rightarrow [3,4,1,5,2] \rightarrow [4,3,1,5,2]$.
Sample Input 2
2 2
1 2
1 2
Output for Sample Input 2
2
1
$p$ changes as follows: $[1,2] \rightarrow [2,1] \rightarrow [1,2]$.
Sample Input 3
10 10
5 6
5 9
8 2
1 6
8 1
7 1
2 6
8 1
7 4
8 10
Output for Sample Input 3
2
3
6
4
6
7
12
7
8
9

Submitted solutions:

code_snippet: #include <bits/stdc++.h>

using namespace std;
using pii = pair<int, int>;
using ll = long long;

constexpr ll M = 1e9 + 7;
constexpr int MAXN = 1e5 + 1;

struct Qry{
    Qry() = default;
    Qry(int x, int y, int l):e(x, y),l(l){};
    pii e;
    int l, r = -1;
    bool united;
};

ll gcd(ll a, ll b, ll &x, ll &y){
    if (b == 0){
        x = 1, y = 0;
        return a;
    }
    ll x1, y1;
    ll g = gcd(b, a % b, x1, y1);
    x = y1;
    y = x1 - (a / b) * y1;
    return g;
}

ll inv(ll a){
    ll x, y;
    gcd(a, M, x, y);
    return (x % M + M) % M;
}

ll mypow(ll a, ll n){
    ll base = a;
    ll ret = 1;
    while (n != 0){
        if (n & 1)
            ret = (ret * base) % M;
        n >>= 1;
        base = base * base % M;
    }
    return ret;
}

vector<vector<ll>> fac(MAXN);
vector<bool> isprime(MAXN, true);
void init(){
    for (int i = 2; i < MAXN; ++i) if (isprime[i]){
        for (int j = i; j < MAXN; j += i)
            fac[j].push_back(i), isprime[j] = false;
        isprime[i] = true;
    }
}

struct LCM{
    vector<map<int, int>> prime;
    int n;
    LCM(int n):prime(n+1),n(n){
        for (int i = 2; i <= n; ++i) if (isprime[i])
            prime[i][0] = 1;
    };
    ll lcm = 1;

    void insert(ll f, ll cnt){
        lcm = lcm * inv(mypow(f, prime[f].rbegin()->first)) % M;
        if (prime[f].find(cnt) == prime[f].end())
            prime[f][cnt] = 0;
        ++prime[f][cnt];
        lcm = lcm * mypow(f, prime[f].rbegin()->first) % M;
    }
    void remove(ll f, ll cnt){
        lcm = lcm * inv(mypow(f, prime[f].rbegin()->first)) % M;
        --prime[f][cnt];
        if (prime[f][cnt] == 0)
            prime[f].erase(cnt);
        lcm = lcm * mypow(f, prime[f].rbegin()->first) % M;
    }
    void add(int a){
        // cerr << "add " << a << '\n';
        for (auto &f : fac[a]){
            int cnt = 0;
            while (a % f == 0)
                a /= f, ++cnt;
            insert(f, cnt);
        }
    }
    void del(int a){
        // cerr << "del " << a << '\n';
        for (auto &f : fac[a]){
            int cnt = 0;
            while (a % f == 0)
                a /= f, ++cnt;
            remove(f, cnt);
        }
    }
    void print(){
        for (int i = 2; i <= n; ++i) if (isprime[i]){
            cerr << i << ": ";
            for (auto &f : prime[i]) if (f.first != 0)
                cerr << f.first << ' ';
            cerr << '\n';
        }
    }
};

struct DSU_s{
    int a, b, sza, szb;
    DSU_s(int a, int sza, int b, int szb):a(a),sza(sza),b(b),szb(szb){};
};

struct DSU{
    vector<int> p, sz;
    stack<DSU_s> op;
    LCM g;

    DSU(int n):p(n + 1), sz(n + 1, 1),g(n + 1){
        iota(p.begin(), p.end(), 0);
        for (int i = 0; i != n; ++i)
            g.add(1);
    }
    int find(int a){
        return (a == p[a]) ? a : find(p[a]);
    }
    bool merge(int a, int b){
        // cerr << "add " << a << ' ' << b << '\n';
        int A = find(a), B = find(b);
        if (A == B) return false;
        if (sz[A] < sz[B])
            swap(A, B);
        op.push(DSU_s(A, sz[A], B, sz[B]));
        g.del(sz[A]), g.del(sz[B]);

        p[B] = A;
        sz[A] += sz[B];
        g.add(sz[A]);
        return true;
    }
    void rollback(){
        if (op.empty()) return;
        auto top = op.top();
        op.pop();
        g.del(sz[top.a]);
        sz[top.a] = top.sza;
        sz[top.b] = top.szb;
        p[top.a] = top.a;
        p[top.b] = top.b;
        g.add(sz[top.a]), g.add(sz[top.b]);
        // cerr << "del" << ' ' << top.a << ' ' << top.b << '\n';
    }
    ll lcm(){
        return g.lcm;
    }
};

struct STree{
    vector<vector<Qry>> qrys;
    vector<int> ans;
    DSU dsu;
    int N;
    STree(int Q, int N):qrys(4 * Q), ans(Q),dsu(N),N(N){};
    void upd(int v, Qry &qry, int ql, int qr, int l, int r){
        if (ql <= l && r <= qr)
            return void(qrys[v].push_back(qry));
        else if (r < ql || qr < l)
            return;
        int mid = (l + r) / 2;
        upd(v << 1, qry, ql, qr, l, mid);
        upd(v << 1 | 1, qry, ql, qr, mid + 1, r);
    }
    void solve(int v, int l, int r){
        if (l > r)
            return;
        for (auto &qry : qrys[v])
            qry.united = dsu.merge(qry.e.first, qry.e.second);
        if (l == r){
            ans[l] = dsu.lcm();
        }
        else{
            int mid = (l + r) / 2;
            solve(v << 1, l, mid);
            solve(v << 1 | 1, mid + 1, r);
        }
        for (auto &qry : qrys[v]) if (qry.united)
            dsu.rollback();
    }
};

int main(){
    cin.tie(0), ios_base::sync_with_stdio(false);
    init();
    int N, Q;
    cin >> N >> Q;
    vector<int> p(N + 1);
    iota(p.begin(), p.end(), 0);
    vector<int> rec(N + 1, -1);
    vector<Qry> qrys;
    
    for (int i = 0; i != Q; ++i){
        int x, y;
        cin >> x >> y;
        if (rec[x] != -1)
            qrys[rec[x]].r = i - 1;
        if (rec[y] != -1)
            qrys[rec[y]].r = i - 1;
        swap(p[x], p[y]);
        rec[x] = qrys.size();
        qrys.emplace_back(x, p[x], i);
        rec[y] = qrys.size();
        qrys.emplace_back(y, p[y], i);
    }
    for (auto &qry : qrys)
        if (qry.r == -1) qry.r = Q - 1;

    STree stree(Q, N);
    for (auto &qry : qrys)
        stree.upd(1, qry, qry.l, qry.r, 0, Q - 1);//, cerr << qry.l << ' ' << qry.r << ' ' << qry.e.first << ' ' << qry.e.second << '\n';
    stree.solve(1, 0, Q - 1);
    for (int i = 0; i < Q; ++i)
        cout << stree.ans[i] << '\n';
    return 0;
}
accuracy: 1
time_ms: 2340
memory_kb: 90128
final_rank: 4

code_snippet: // AOJ #2855 Permutation Period
// 2025.3.28

#include <bits/stdc++.h>
using namespace std;

#define gc() getchar_unlocked()
#define pc(c) putchar_unlocked(c)
using ll = long long;

int Cin() {
	int n = 0; int c = gc();
	do n = 10*n + (c & 0xf), c = gc(); while (c >= '0');
	return n;
}

void Cout(int n) {
	char b[30];
	if (!n) pc('0');
	else {
		if (n < 0) pc('-'), n = -n;
		int i = 0; while (n) b[i++] = n % 10 + '0', n /= 10;
		while (i--) pc(b[i]);
	}
    pc('\n');
}

const int MOD = 1000000007;
const int MAXN = 100100;
const int BLOCK = 333;

int tot;
int prime[MAXN];
int isComposite[MAXN];
int freq[340][20];
int maxExp[340];
int cnt[MAXN];
int ans;
int inv[MAXN];
int arr[MAXN];

struct Node { int sz, v, l, r, p; } tree[MAXN];

void init() {
    int N = 100000;
    tot = 0;
    for (int i = 2; i <= N; i++) {
        if (!isComposite[i]) prime[tot++] = i;
        for (int j = 0; j < tot && prime[j] * i <= N; j++) {
            isComposite[i * prime[j]] = 1;
            if (i % prime[j] == 0) break;
        }
    }
    inv[1] = 1;
    for (int i = 2; i <= N; i++) inv[i] = (MOD - MOD / i * (ll)inv[MOD % i] % MOD) % MOD;
    for (int i = 0; i < BLOCK; i++) freq[i][0] = 1;
    ans = 1;
}

void add(int x) {
    for (int i = 0, expCount; i < tot && prime[i] < BLOCK; i++) {
        if (x % prime[i] == 0) {
            expCount = 1;
            x /= prime[i];
            while (x % prime[i] == 0) {
                expCount++;
                x /= prime[i];
            }
            freq[i][expCount]++;
            while (maxExp[i] < expCount) {
                maxExp[i]++;
                ans = (int)((ll)ans * prime[i] % MOD);
            }
        }
    }
    if (x > 1) {
        cnt[x]++;
        if (cnt[x] == 1) ans = (int)((ll)ans * x % MOD);
    }
}

void del(int x) {
    for (int i = 0, expCount; i < tot && prime[i] < BLOCK; i++) {
        if (x % prime[i] == 0) {
            expCount = 1;
            x /= prime[i];
            while (x % prime[i] == 0) {
                expCount++;
                x /= prime[i];
            }
            freq[i][expCount]--;
            if (maxExp[i] == expCount && freq[i][expCount] == 0)
                while (freq[i][maxExp[i]] == 0) {
                    maxExp[i]--;
                    ans = (int)((ll)ans * inv[prime[i]] % MOD);
                }
        }
    }
    if (x > 1) {
        cnt[x]--;
        if (cnt[x] == 0) ans = (int)((ll)ans * inv[x] % MOD);
    }
}

void lrot(int x) {
    int par = tree[x].p;
    int g = tree[par].p;
    int b = tree[x].r;
    tree[x].sz = tree[par].sz;
    int leftSize = tree[tree[x].l].sz;
    tree[par].sz -= leftSize + 1;
    if (g) {
        if (tree[g].l == par) tree[g].l = x;
        else tree[g].r = x;
    }
    tree[x].p = g;
    tree[x].r = par;
    tree[par].p = x;
    tree[par].l = b;
    if (b) tree[b].p = par;
}

void rrot(int x) {
    int par = tree[x].p;
    int g = tree[par].p;
    int b = tree[x].l;
    tree[x].sz = tree[par].sz;
    int rightSize = tree[tree[x].r].sz;
    tree[par].sz -= rightSize + 1;
    if (g) {
        if (tree[g].l == par) tree[g].l = x;
        else tree[g].r = x;
    }
    tree[x].p = g;
    tree[x].l = par;
    tree[par].p = x;
    tree[par].r = b;
    if (b) tree[b].p = par;
}

void splay(int x) {
    while (tree[x].p) {
        int p = tree[x].p;
        int g = tree[p].p;
        if (g) {
            if      (x == tree[p].l && p == tree[g].l) lrot(p), lrot(x);
            else if (x == tree[p].l && p == tree[g].r) lrot(x), rrot(x);
            else if (x == tree[p].r && p == tree[g].l) rrot(x), lrot(x);
            else                                       rrot(p), rrot(x);
        } else if (x == tree[p].l) lrot(x);
        else rrot(x);
    }
}

int findRoot(int x) {
    while (tree[x].p) x = tree[x].p;
    return x;
}

int main() {
    init();
    int n = Cin(), q = Cin();
    for (int i = 1; i <= n; i++) tree[i] = {1, i, 0, 0, 0};
    for (int i = 1; i <= n; i++) arr[i] = i;
    while (q--) {
        int l = Cin(), r = Cin();
        swap(arr[l], arr[r]);
        l = arr[l], r = arr[r];
        splay(l);
        int rt = findRoot(r);
        if (l == rt) {
            del(tree[l].sz);
            int nl = tree[l].r;
            tree[l].r = 0;
            if (nl) tree[nl].p = 0;
            tree[l].sz -= tree[nl].sz;
            if (l == findRoot(r)) {
                splay(r);
                int nr = tree[r].r;
                tree[r].r = nl;
                if (nl) tree[nl].p = r;
                if (nr) tree[nr].p = 0;
                tree[r].sz += tree[nl].sz - tree[nr].sz;
                add(tree[r].sz);
                add(tree[nr].sz);
            } else {
                splay(r);
                int nr = tree[r].r;
                tree[r].r = 0;
                tree[l].r = nr;
                if (nr) tree[nr].p = l;
                tree[r].sz -= tree[nr].sz;
                tree[l].sz += tree[nr].sz;
                add(tree[l].sz);
                add(tree[r].sz);
            }
        } else {
            splay(r);
            del(tree[l].sz);
            del(tree[r].sz);
            int nl = tree[l].r, nr = tree[r].r;
            tree[l].r = nr;
            if (nr) tree[nr].p = l;
            tree[l].sz += tree[nr].sz - tree[nl].sz;
            tree[r].r = nl;
            if (nl) tree[nl].p = r;
            tree[r].sz += tree[nl].sz - tree[nr].sz;
            while (tree[l].r) l = tree[l].r;
            splay(l);
            tree[l].r = r;
            tree[r].p = l;
            tree[l].sz += tree[r].sz;
            add(tree[l].sz);
        }
        Cout(ans);
    }
    return 0;
}
accuracy: 1
time_ms: 90
memory_kb: 6912
final_rank: 1

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1000000007;
const int N = 100005;

int n, q, sq;
pair<int, int> a[100005];
int c[100005], sz[100005], p[100005], ch[100005], v[100005];
int mp[100005];
int pr[100005];
vector<ll> ps;
vector<ll> sqr[100005];

vector<pair<int, int>> fac(int x){
    vector<pair<int, int>> r;
    for(int p : ps){
        if((ll)p*p > x) break;
        if(x%p == 0){
            int cnt = 0;
            while(x%p == 0){
                cnt++;
                x /= p;
            }
            r.push_back({p, cnt});
        }
    }
    if(x > 1) r.push_back({x, 1});
    return r;
}

ll modp(ll b, ll e){
    ll r = 1;
    while(e){
        if(e&1) r = (r*b)%mod;
        b = (b*b)%mod;
        e >>= 1;
    }
    return r;
}

unordered_map<int, int> be;

ll lcmv(const vector<int>& v){
    unordered_map<int, int> mx;
    for(auto [x, y] : be) mx[x] = y;
    for(int x : v){
        vector<pair<int, int>> f = fac(x);
        for(auto &p : f) mx[p.first] = max(mx[p.first], p.second);
    }
    ll ret = 1;
    for(auto &e : mx) ret = (ret*modp(e.first, e.second)) % mod;
    return ret;
}

vector<int> get(int cnt){
    vector<int> t(cnt+1, 0);
    vector<int> r;
    for(int k=1; k<=cnt; k++){
        if(!t[k]){
            int s = 0, tk = k;
            while(1){
                t[tk] = 1;
                s += sz[tk];
                if (t[p[tk]]) break;
                tk = p[tk];
            }
            r.push_back(s);
        }
    }
    return r;
}

void dfs(int st, int id, vector<bool>& proc){
    int cur = st;
    sz[id] = 0;
    while(!proc[cur]){
        proc[cur] = true;
        mp[cur] = id;
        sz[id]++;
        cur = c[cur];
    }
}

void sv(int l){
    for(int i=2; i<=l; i++){
        if(pr[i]) continue;
        ps.push_back(i);
        for(ll j=i; j<=l; j*=i){
			sqr[i].push_back(j);
		}
        for(ll j=i*2; j<=l; j+=i){
			pr[j] = 1;
		}
    }
}

int main(){
    sv(100000);
    scanf("%d %d", &n, &q);
    sq = 500;
    for(int i=0; i<q; i++){
		scanf("%d %d", &a[i].first, &a[i].second);
	}
    for(int i=1; i<=n; i++){
		c[i] = i;
	}
    for(int bs=0; bs<q; bs+=sq){
        be.clear();
        set<int> st;
        for(int j=bs; j<min(q, bs+sq); j++){
            st.insert(a[j].first);
            st.insert(a[j].second);
        }
        int cnt = 0;
        for(int j=1; j<=n; j++){
			mp[j] = -1;
			v[j] = 0;
		}
        vector<int> bc;
        for(int j=1; j<=n; j++){
            if(!v[j]){
                int s = (st.find(j) == st.end()) ? 1 : 0, cur = 0, tj = j, pj = j;
                while(1){
                    v[tj] = 1;
                    cur++;
                    if((st.find(c[tj]) != st.end()) || v[c[tj]] || (((st.find(c[tj]) == st.end()) ? 1 : 0) ^ s)){
                        if(!(st.find(c[tj]) != st.end()) && !((((st.find(c[tj]) == st.end()) ? 1 : 0) ^ s)) && v[c[tj]] && pj == j){
                            bc.push_back(cur);
                            cur = 0;
                            break;
                        }
                        cnt++;
                        int nx = cnt + 1;
                        if(v[c[tj]]) nx = (mp[c[tj]] == -1) ? cnt : mp[c[tj]];
                        p[cnt] = nx;
                        ch[nx] = cnt;
                        sz[cnt] = cur;
                        cur = 0;
                        mp[pj] = cnt;
                        pj = c[tj];
                        if(v[c[tj]]) break;
                    }
                    tj = c[tj];
                    s = (st.find(tj) == st.end()) ? 1 : 0;
                }
            }
        }
        for(auto x : bc){
            vector<pair<int, int>> f = fac(x);
            for(auto &p : f) be[p.first] = max(be[p.first], p.second);
        }
        for(int j=bs; j<min(q, bs+sq); j++){
            auto [u, v] = a[j];
            int u_ = mp[u], v_ = mp[v];
            swap(p[u_], p[v_]);
            swap(ch[u_], ch[v_]);
            vector<int> af = get(cnt);
            ll ans = lcmv(af);
            printf("%lld\n", ans);
        }
        for(int j=bs; j<min(q, bs+sq); j++){
			swap(c[a[j].first], c[a[j].second]);
		}
    }
}
accuracy: 1
time_ms: 4520
memory_kb: 9688
final_rank: 2

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1000000007;
const int MAXN = 100005;

int n, q, sq;
pair<int, int> a[MAXN];
int c[MAXN];       // 순열, 1-indexed
int sz[MAXN];      // 압축된 트리에서 각 노드(압축된 사이클)의 길이
int par[MAXN];     // 압축 트리 상의 부모
int chd[MAXN];     // 압축 트리 상의 자식
int vst[MAXN];     // 전체 순열 방문 배열
int mp[MAXN];      // 각 원소가 압축 트리 상에서 어느 노드에 속하는지 (압축된 노드 번호)
int prime[MAXN];   // sieve용 (0이면 소수)
vector<ll> ps;     // 소수 목록
vector<ll> sqa[MAXN];  // (원래 코드와 동일)

// x의 소인수분해 (x가 작으므로 단순 반복)
vector<pair<int,int>> factorize(int x) {
    vector<pair<int,int>> res;
    for (int p : ps) {
        if ((ll)p * p > x) break;
        if(x % p == 0) {
            int cnt = 0;
            while(x % p == 0) {
                cnt++;
                x /= p;
            }
            res.push_back({p, cnt});
        }
    }
    if(x > 1) res.push_back({x, 1});
    return res;
}
 
// 모듈러 거듭제곱
ll modExp(ll base, ll exp) {
    ll res = 1;
    while(exp) {
        if(exp & 1) res = (res * base) % mod;
        base = (base * base) % mod;
        exp >>= 1;
    }
    return res;
}

unordered_map<int,int> baseExp;
 
// 주어진 사이클 길이들의 벡터를 받아, 각 길이를 소인수분해하여 전체 LCM을 계산
ll calcLCM(const vector<int>& cycleLengths) {
	unordered_map<int,int> maxExp;
	for(auto [x, y] : baseExp){
		maxExp[x] = y;
	}
    for (int len : cycleLengths) {
        vector<pair<int,int>> fac = factorize(len);
        for (auto &p : fac) {
            maxExp[p.first] = max(maxExp[p.first], p.second);
        }
    }
    ll ans = 1;
    for (auto &entry : maxExp) {
        ans = (ans * modExp(entry.first, entry.second)) % mod;
    }
    return ans;
}
 
// 블록 내에서 압축 트리(affected 영역)에서 각 연결 컴포넌트별 총 길이를 구함.
// 여기서 cnt는 압축 트리 상의 노드 개수.
vector<int> getAffectedCycleLengths(int cnt) {
    vector<int> tmp(cnt+1, 0);
    vector<int> compCycleLengths;
    for (int k = 1; k <= cnt; k++) {
        if (!tmp[k]) {
            int sum = 0;
            int tk = k;
            while (true) {
                tmp[tk] = 1;
                sum += sz[tk];
                if (tmp[ par[tk] ]) break;
                tk = par[tk];
            }
            compCycleLengths.push_back(sum);
        }
    }
    return compCycleLengths;
}
 
// DFS로 압축된 사이클 하나를 구함 (affected 영역에 대해서만)
// start부터 시작해서, 압축 트리 상에서 하나의 덩어리(압축된 사이클)를 구성하며, 해당 덩어리의 길이를 sz[newId]에 누적.
void dfsCycle(int start, int newId, vector<bool>& processed) {
    int cur = start;
    sz[newId] = 0;
    while (!processed[cur]) {
        processed[cur] = true;
        mp[cur] = newId;
        sz[newId]++; 
        cur = c[cur];
    }
}
 
// Sieve를 통해 소수 목록 구축
void sievePrimes(int limit) {
    for (int i = 2; i <= limit; i++){
        if(prime[i]) continue;
        ps.push_back(i);
        for (ll j = i; j <= limit; j *= i){
            sqa[i].push_back(j);
        }
        for (ll j = i * 2; j <= limit; j += i){
            prime[j] = 1;
        }
    }
}
 
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    sievePrimes(100000);
    
    cin >> n >> q;
    sq = 500;
    for (int i = 0; i < q; i++){
        int u, v;
        cin >> u >> v;
        a[i] = {u, v};
    }
    for (int i = 1; i <= n; i++){
        c[i] = i;
    }
 
    // 블록 단위 처리: 각 블록마다 쿼리 블록에 포함되지 않는 부분은 "압축"해서 관리함.
    for (int blockStart = 0; blockStart < q; blockStart += sq) {
		baseExp.clear();
        // st: 이번 블록의 쿼리에서 등장하는 모든 노드 (affected 영역)
        set<int> st;
        for (int j = blockStart; j < min(q, blockStart + sq); j++){
            st.insert(a[j].first);
            st.insert(a[j].second);
        }
 
        int cnt = 0; // 압축 트리 상의 노드 번호 (1부터 cnt)
        for (int j = 1; j <= n; j++){
            mp[j] = -1;
        }
        for (int j = 1; j <= n; j++){
            vst[j] = 0;
        }
 
        // baseCycleLengths: 쿼리 블록에 등장하지 않은(affected되지 않은) 부분을 압축한 사이클들의 길이
        vector<int> baseCycleLengths;
 
        // 전체 순열에 대해, st에 포함되지 않은 부분은 한 덩어리(압축 사이클)로 처리
        for (int j = 1; j <= n; j++){
            if (!vst[j]) {
                int s = (st.find(j) == st.end()) ? 1 : 0;
                int cur = 0;
                int tj = j;
                int pj = j;
                while (true) {
                    vst[tj] = 1;
                    cur++;
                    // 조건: 다음 노드가 affected 영역에 포함되거나, 이미 방문됐거나, 상태 변화가 발생하면 종료
                    if ( (st.find(c[tj]) != st.end()) ||
                         vst[c[tj]] ||
                         (((st.find(c[tj]) == st.end()) ? 1 : 0) ^ s) ) {
                        // 만약 affected되지 않은 부분이고, 순환해서 처음으로 돌아왔으면, 한 사이클 완성
                        if ( !(st.find(c[tj]) != st.end()) &&
                             !((((st.find(c[tj]) == st.end()) ? 1 : 0) ^ s)) &&
                             vst[c[tj]] && pj == j) {
                            baseCycleLengths.push_back(cur);
                            cur = 0;
                            break;
                        }
                        cnt++;
                        int nxt = cnt + 1;
                        if (vst[c[tj]]) {
                            if (mp[c[tj]] == -1) {
                                nxt = cnt;
                            } else {
                                nxt = mp[c[tj]];
                            }
                        }
                        par[cnt] = nxt;
                        chd[nxt] = cnt;
                        sz[cnt] = cur;
                        cur = 0;
                        mp[pj] = cnt;
                        pj = c[tj];
                        if (vst[c[tj]])
                            break;
                    }
                    tj = c[tj];
                    s = (st.find(tj) == st.end()) ? 1 : 0;
                }
            }
        }
 
        // 이제 baseCycleLengths에는 쿼리 블록에 등장하지 않은 부분의 압축된 사이클 길이들이 들어있고,
        // 압축 트리의 정보(par, chd, sz, mp)로 affected 영역(쿼리 블록에 등장한 부분)의 사이클들이 관리됨.
 
        // 블록 내 쿼리 처리
        // affected 영역에 대해, 압축 트리 상의 노드들 (번호 1 ~ cnt) 중 affected된 부분은
        // swap으로 업데이트된 후 재압축되어 새로운 사이클 길이들이 형성된다.
		for(auto x : baseCycleLengths){
			vector<pair<int,int>> fac = factorize(x);
			for (auto &p : fac) {
				baseExp[p.first] = max(baseExp[p.first], p.second);
			}
		}
        for (int j = blockStart; j < min(q, blockStart + sq); j++){
            auto [u, v] = a[j];
            int u_ = mp[u], v_ = mp[v];
            swap(par[u_], par[v_]);
            swap(chd[u_], chd[v_]);
 
            // affected 영역의 새 압축 사이클 길이들을 구함
            vector<int> affectedCycleLengths = getAffectedCycleLengths(cnt);
            // 이제 baseCycleLengths와 affectedCycleLengths를 합친 전체 사이클 길이들에서 LCM을 구해야 함.
            ll ans = calcLCM(affectedCycleLengths);
            cout << ans << "\n";
        }
 
        // 블록 내 쿼리 처리 후, 실제 순열 c에도 swap 반영 (압축된 정보는 재구성됨)
        for (int j = blockStart; j < min(q, blockStart + sq); j++){
            auto [u, v] = a[j];
            swap(c[u], c[v]);
        }
    }
    return 0;
}
accuracy: 1
time_ms: 4720
memory_kb: 9592
final_rank: 3

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1000000007;
const int MAXN = 100005;

int n, q, sq;
pair<int, int> a[MAXN];
int c[MAXN];       // 순열, 1-indexed
int sz[MAXN];      // 압축된 트리에서 각 노드(압축된 사이클)의 길이
int par[MAXN];     // 압축 트리 상의 부모
int chd[MAXN];     // 압축 트리 상의 자식
int vst[MAXN];     // 전체 순열 방문 배열
int mp[MAXN];      // 각 원소가 압축 트리 상에서 어느 노드에 속하는지 (압축된 노드 번호)
int prime[MAXN];   // sieve용 (0이면 소수)
vector<ll> ps;     // 소수 목록
vector<ll> sqa[MAXN];  // (원래 코드와 동일)

// x의 소인수분해 (x가 작으므로 단순 반복)
vector<pair<int,int>> factorize(int x) {
    vector<pair<int,int>> res;
    for (int p : ps) {
        if ((ll)p * p > x) break;
        if(x % p == 0) {
            int cnt = 0;
            while(x % p == 0) {
                cnt++;
                x /= p;
            }
            res.push_back({p, cnt});
        }
    }
    if(x > 1) res.push_back({x, 1});
    return res;
}
 
// 모듈러 거듭제곱
ll modExp(ll base, ll exp) {
    ll res = 1;
    while(exp) {
        if(exp & 1) res = (res * base) % mod;
        base = (base * base) % mod;
        exp >>= 1;
    }
    return res;
}

unordered_map<int,int> baseExp;
 
// 주어진 사이클 길이들의 벡터를 받아, 각 길이를 소인수분해하여 전체 LCM을 계산
ll calcLCM(const vector<int>& cycleLengths) {
	unordered_map<int,int> maxExp;
	for(auto [x, y] : baseExp){
		maxExp[x] = y;
	}
    for (int len : cycleLengths) {
        vector<pair<int,int>> fac = factorize(len);
        for (auto &p : fac) {
            maxExp[p.first] = max(maxExp[p.first], p.second);
        }
    }
    ll ans = 1;
    for (auto &entry : maxExp) {
        ans = (ans * modExp(entry.first, entry.second)) % mod;
    }
    return ans;
}
 
// 블록 내에서 압축 트리(affected 영역)에서 각 연결 컴포넌트별 총 길이를 구함.
// 여기서 cnt는 압축 트리 상의 노드 개수.
vector<int> getAffectedCycleLengths(int cnt) {
    vector<int> tmp(cnt+1, 0);
    vector<int> compCycleLengths;
    for (int k = 1; k <= cnt; k++) {
        if (!tmp[k]) {
            int sum = 0;
            int tk = k;
            while (true) {
                tmp[tk] = 1;
                sum += sz[tk];
                if (tmp[ par[tk] ]) break;
                tk = par[tk];
            }
            compCycleLengths.push_back(sum);
        }
    }
    return compCycleLengths;
}
 
// DFS로 압축된 사이클 하나를 구함 (affected 영역에 대해서만)
// start부터 시작해서, 압축 트리 상에서 하나의 덩어리(압축된 사이클)를 구성하며, 해당 덩어리의 길이를 sz[newId]에 누적.
void dfsCycle(int start, int newId, vector<bool>& processed) {
    int cur = start;
    sz[newId] = 0;
    while (!processed[cur]) {
        processed[cur] = true;
        mp[cur] = newId;
        sz[newId]++; 
        cur = c[cur];
    }
}
 
// Sieve를 통해 소수 목록 구축
void sievePrimes(int limit) {
    for (int i = 2; i <= limit; i++){
        if(prime[i]) continue;
        ps.push_back(i);
        for (ll j = i; j <= limit; j *= i){
            sqa[i].push_back(j);
        }
        for (ll j = i * 2; j <= limit; j += i){
            prime[j] = 1;
        }
    }
}
 
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    sievePrimes(100000);
    
    cin >> n >> q;
    sq = 500;
    for (int i = 0; i < q; i++){
        int u, v;
        cin >> u >> v;
        a[i] = {u, v};
    }
    for (int i = 1; i <= n; i++){
        c[i] = i;
    }
 
    // 블록 단위 처리: 각 블록마다 쿼리 블록에 포함되지 않는 부분은 "압축"해서 관리함.
    for (int blockStart = 0; blockStart < q; blockStart += sq) {
        // st: 이번 블록의 쿼리에서 등장하는 모든 노드 (affected 영역)
        set<int> st;
        for (int j = blockStart; j < min(q, blockStart + sq); j++){
            st.insert(a[j].first);
            st.insert(a[j].second);
        }
 
        int cnt = 0; // 압축 트리 상의 노드 번호 (1부터 cnt)
        for (int j = 1; j <= n; j++){
            mp[j] = -1;
        }
        for (int j = 1; j <= n; j++){
            vst[j] = 0;
        }
 
        // baseCycleLengths: 쿼리 블록에 등장하지 않은(affected되지 않은) 부분을 압축한 사이클들의 길이
        vector<int> baseCycleLengths;
 
        // 전체 순열에 대해, st에 포함되지 않은 부분은 한 덩어리(압축 사이클)로 처리
        for (int j = 1; j <= n; j++){
            if (!vst[j]) {
                int s = (st.find(j) == st.end()) ? 1 : 0;
                int cur = 0;
                int tj = j;
                int pj = j;
                while (true) {
                    vst[tj] = 1;
                    cur++;
                    // 조건: 다음 노드가 affected 영역에 포함되거나, 이미 방문됐거나, 상태 변화가 발생하면 종료
                    if ( (st.find(c[tj]) != st.end()) ||
                         vst[c[tj]] ||
                         (((st.find(c[tj]) == st.end()) ? 1 : 0) ^ s) ) {
                        // 만약 affected되지 않은 부분이고, 순환해서 처음으로 돌아왔으면, 한 사이클 완성
                        if ( !(st.find(c[tj]) != st.end()) &&
                             !((((st.find(c[tj]) == st.end()) ? 1 : 0) ^ s)) &&
                             vst[c[tj]] && pj == j) {
                            baseCycleLengths.push_back(cur);
                            cur = 0;
                            break;
                        }
                        cnt++;
                        int nxt = cnt + 1;
                        if (vst[c[tj]]) {
                            if (mp[c[tj]] == -1) {
                                nxt = cnt;
                            } else {
                                nxt = mp[c[tj]];
                            }
                        }
                        par[cnt] = nxt;
                        chd[nxt] = cnt;
                        sz[cnt] = cur;
                        cur = 0;
                        mp[pj] = cnt;
                        pj = c[tj];
                        if (vst[c[tj]])
                            break;
                    }
                    tj = c[tj];
                    s = (st.find(tj) == st.end()) ? 1 : 0;
                }
            }
        }
 
        // 이제 baseCycleLengths에는 쿼리 블록에 등장하지 않은 부분의 압축된 사이클 길이들이 들어있고,
        // 압축 트리의 정보(par, chd, sz, mp)로 affected 영역(쿼리 블록에 등장한 부분)의 사이클들이 관리됨.
 
        // 블록 내 쿼리 처리
        // affected 영역에 대해, 압축 트리 상의 노드들 (번호 1 ~ cnt) 중 affected된 부분은
        // swap으로 업데이트된 후 재압축되어 새로운 사이클 길이들이 형성된다.
		for(auto x : baseCycleLengths){
			vector<pair<int,int>> fac = factorize(x);
			for (auto &p : fac) {
				baseExp[p.first] = max(baseExp[p.first], p.second);
			}
		}
        for (int j = blockStart; j < min(q, blockStart + sq); j++){
            auto [u, v] = a[j];
            int u_ = mp[u], v_ = mp[v];
            swap(par[u_], par[v_]);
            swap(chd[u_], chd[v_]);
 
            // affected 영역의 새 압축 사이클 길이들을 구함
            vector<int> affectedCycleLengths = getAffectedCycleLengths(cnt);
            // 이제 baseCycleLengths와 affectedCycleLengths를 합친 전체 사이클 길이들에서 LCM을 구해야 함.
            ll ans = calcLCM(affectedCycleLengths);
            cout << ans << "\n";
        }
 
        // 블록 내 쿼리 처리 후, 실제 순열 c에도 swap 반영 (압축된 정보는 재구성됨)
        for (int j = blockStart; j < min(q, blockStart + sq); j++){
            auto [u, v] = a[j];
            swap(c[u], c[v]);
        }
    }
    return 0;
}
accuracy: 0.2962962962962963
time_ms: 2300
memory_kb: 9052
final_rank: 5

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1000000007;
const int MAXN = 100005;

int n, q, sq;
pair<int, int> a[MAXN];
int c[MAXN];        // 순열, 1-indexed
int sz[MAXN];       // 압축된 사이클 내 구간 길이
int par[MAXN];      // 압축 트리에서 부모 정보
int chd[MAXN];      // 압축 트리에서 자식 정보
int vst[MAXN];      // DFS 방문 배열 (전체 순열용)
int mp[MAXN];       // 각 노드가 압축 트리 상에서 어떤 노드에 대응되는지 (매핑)
int prime[MAXN];    // sieve용 (0이면 소수)
vector<ll> ps;      // 소수 목록
vector<ll> sqa[MAXN];  // (원래 코드와 동일)
 
// factorize: x의 소인수분해 (x가 작으므로 단순 반복)
vector<pair<int,int>> factorize(int x) {
    vector<pair<int,int>> res;
    for (int p : ps) {
        if ((ll)p * p > x) break;
        if(x % p == 0) {
            int cnt = 0;
            while(x % p == 0) {
                cnt++;
                x /= p;
            }
            res.push_back({p, cnt});
        }
    }
    if(x > 1) res.push_back({x, 1});
    return res;
}
 
// 모듈러 거듭제곱
ll modExp(ll base, ll exp) {
    ll res = 1;
    while(exp) {
        if(exp & 1) res = (res * base) % mod;
        base = (base * base) % mod;
        exp >>= 1;
    }
    return res;
}
 
// DFS로 압축된 사이클 하나를 구함 (affected 영역에 대해서만)
void dfsCycle(int start, int newId, vector<bool>& processed) {
    int cur = start;
    // 초기화: 해당 사이클 노드들 초기화
    // (newId에 해당하는 벡터는 미리 clear되어 있다고 가정)
    while (!processed[cur]) {
        processed[cur] = true;
        mp[cur] = newId;
        // newId에 해당하는 압축 사이클에 원래 노드 cur를 저장 (필요시 사용)
        // 여기서는 사이클 길이 계산만 하므로, 굳이 저장하지 않아도 됨.
        // 다만 기존 코드와 동일하게 cycleNodes 대신 sz[]에 길이를 누적할 예정임.
        cur = c[cur];
        sz[newId]++; 
    }
}
 
// LCM 계산: 현재 활성(압축) 사이클들의 길이 정보를 바탕으로
// 모든 사이클 길이를 factorize하여, 각 소수별 최대 지수를 구한 후 최종 LCM을 계산
ll calcLCM(const vector<int>& cycleLengths) {
    unordered_map<int,int> maxExp;
    for (int len : cycleLengths) {
        vector<pair<int,int>> fac = factorize(len);
        for (auto &p : fac) {
            maxExp[p.first] = max(maxExp[p.first], p.second);
        }
    }
    ll ans = 1;
    for (auto &entry : maxExp) {
        ans = (ans * modExp(entry.first, entry.second)) % mod;
    }
    return ans;
}
 
// 블록 내부에서 압축 트리(affected 영역)에서 각 연결 컴포넌트별 총 길이를 계산하여 LCM에 반영
ll calcLCM_fromTree(int cnt) {
    vector<int> tmp(cnt+1, 0);
    vector<int> compCycleLengths;
    for (int k = 1; k <= cnt; k++) {
        if (!tmp[k]) {
            int sum = 0;
            int tk = k;
            while (true) {
                tmp[tk] = 1;
                sum += sz[tk];
                if (tmp[ par[tk] ]) {
                    break;
                }
                tk = par[tk];
            }
            compCycleLengths.push_back(sum);
        }
    }
    return calcLCM(compCycleLengths);
}
 
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
 
    // Sieve 및 소수 목록 구축
    for (int i = 2; i <= 100000; i++){
        if(prime[i]) continue;
        ps.push_back(i);
        for (ll j = i; j <= 100000; j *= i){
            sqa[i].push_back(j);
        }
        for (ll j = i * 2; j <= 100000; j += i){
            prime[j] = 1;
        }
    }
 
    cin >> n >> q;
    sq = 500;
    for (int i = 0; i < q; i++){
        int u, v;
        cin >> u >> v;
        a[i] = {u, v};
    }
    for (int i = 1; i <= n; i++){
        c[i] = i;
    }
 
    // 블록 단위 처리: 각 블록마다 쿼리 블록에 포함되지 않는(affected되지 않는) 부분은 압축해서 관리
    for (int blockStart = 0; blockStart < q; blockStart += sq) {
        // st: 현재 블록에 등장하는 모든 노드 (affected 영역)
        set<int> st;
        for (int j = blockStart; j < min(q, blockStart + sq); j++){
            st.insert(a[j].first);
            st.insert(a[j].second);
        }
 
        int cnt = 0; // 압축 트리 상의 노드 번호 (1부터 cnt)
        for (int j = 1; j <= n; j++){
            mp[j] = -1;
        }
        for (int j = 1; j <= n; j++){
            vst[j] = 0;
        }
 
        // vvv: 압축된(affected되지 않은) 사이클들의 길이 저장 (나중에 base LCM 계산)
        vector<int> baseCycleLengths;
 
        // 압축 트리 구성: 전체 순열을 순회하면서,
        // st에 포함되지 않은 부분은 하나의 덩어리로 압축해서 처리
        for (int j = 1; j <= n; j++){
            if(!vst[j]){
                int s = (st.find(j) == st.end());
                int cur = 0;
                int tj = j;
                int pj = j;
                while (true) {
                    vst[tj] = 1;
                    cur++;
                    // 아래 조건은 원래 코드와 동일한 논리로, st에 포함되었거나 방문되었거나, 상태가 달라지는 경우 처리
                    if ((st.find(c[tj]) != st.end()) || vst[c[tj]] || ((((st.find(c[tj]) == st.end()) ? 1 : 0) ^ s))) {
                        if ((! (st.find(c[tj]) != st.end()) && !((((st.find(c[tj]) == st.end()) ? 1 : 0) ^ s)) && vst[c[tj]] && pj == j)) {
                            baseCycleLengths.push_back(cur);
                            cur = 0;
                            break;
                        }
                        cnt++;
                        int nxt = cnt + 1;
                        if (vst[c[tj]]) {
                            if (mp[c[tj]] == -1) {
                                nxt = cnt;
                            } else {
                                nxt = mp[c[tj]];
                            }
                        }
                        par[cnt] = nxt;
                        chd[nxt] = cnt;
                        sz[cnt] = cur;
                        cur = 0;
                        mp[pj] = cnt;
                        pj = c[tj];
                        if (vst[c[tj]])
                            break;
                    }
                    tj = c[tj];
                    s = (st.find(tj) == st.end());
                }
            }
        }
 
        // base LCM 계산: 쿼리 블록에 포함되지 않은(압축된) 부분의 사이클 길이들로부터 LCM을 미리 계산
        ll baseLCM = calcLCM(baseCycleLengths);
 
        // 블록 내 쿼리 처리 (affected 영역은 위의 압축 트리에서 관리됨)
        // affected 영역에 대해서는 트리 구조(par, chd, sz)가 업데이트되며,
        // 연결된 각 컴포넌트의 총 길이를 factorize하여 LCM에 반영
        for (int j = blockStart; j < min(q, blockStart + sq); j++){
            auto [u, v] = a[j];
            int u_ = mp[u], v_ = mp[v];
            swap(par[u_], par[v_]);
            swap(chd[u_], chd[v_]);
 
            ll compLCM = calcLCM_fromTree(cnt);
            ll ans = (baseLCM * compLCM) % mod;
            cout << ans << "\n";
        }
 
        // 블록 내 쿼리 처리 후, 실제 순열 c에 대해 swap을 반영
        for (int j = blockStart; j < min(q, blockStart + sq); j++){
            auto [u, v] = a[j];
            swap(c[u], c[v]);
        }
    }
    return 0;
}
accuracy: 0.2962962962962963
time_ms: 2320
memory_kb: 9040
final_rank: 6