设两棵多叉树
U
,
V
U,V
U,V,其根节点为
u
,
v
u,v
u,v,大小为
s
i
z
U
,
s
i
z
V
siz_U,siz_V
sizU,sizV,各自的答案为
w
U
,
w
V
w_U,w_V
wU,wV。
若此时把
U
U
U 合并到
V
V
V 上,此时的根节点
v
v
v 只能填
0
0
0,下面分成了两块:一块
s
i
z
U
siz_U
sizU 个,一块
s
i
z
V
−
1
siz_V-1
sizV−1 个,两块不影响。所以答案为
w
U
×
w
V
×
C
n
m
w_U \times w_V \times C_n^m
wU×wV×Cnm。然后用并查集维护一下,组合数用阶乘逆元算。
//P5689
#include <bits/stdc++.h>
using namespace std;
const int N = 3e5 + 10, mod = 1e9 + 7;
long long w[N], A[N], invA[N];
int n, q, fa[N], siz[N], ans;
int gf(int x){ return fa[x] == x ? x : fa[x] = gf(fa[x]); }
long long qp(long long a, long long b){
long long ans = 1;
while(b){ if(b&1) ans = ans * a % mod; a = a * a % mod; b >>= 1; }
return ans;
}
long long C(long long n, long long m){
return A[n] * invA[m] % mod * invA[n-m] % mod;
}
int main(){
scanf("%d%d", &n, &q);
siz[0] = w[0] = 1, A[0] = 1;
for(int i = 1; i <= n; ++ i)
fa[i] = i, siz[i] = w[i] = 1, A[i] = A[i-1] * i % mod;
invA[n] = qp(A[n], mod-2);
for(int i = n-1; i >= 0; -- i) invA[i] = invA[i+1] * (i+1) % mod;
for(int i = 1, op, x, y; i <= q; ++ i){
scanf("%d%d", &op, &x), x = (x+ans) % n;
if(op == 1){
scanf("%d", &y), y = (y+ans) % n;
x = gf(x), y = gf(y);
siz[y] += siz[x], fa[x] = y;
// printf("- %lld %lld %lld\n", siz[y]-1, siz[x], C(siz[y]-1,siz[x]));
w[y] = w[x] * w[y] % mod * C(siz[y] - 1, siz[x]) % mod;
} else {
x = gf(x), ans = (int)w[x];
printf("%d\n", ans);
}
}
return 0;
}