Loading [MathJax]/extensions/tex2jax.js

「Fortuna OJ」Aug 4th – Group A 解题报告

今天被各路神仙吊打,顺利 gg。

A – Forging 锻造

在考场上我推了个有后效性的 DP,还以为是高斯消元,然后看到数据范围就 GG 了。这道题主要是把一些东西给转换掉了。

首先,对一个概率为\(p\)的事件,它的期望次数是\(\frac{1}{p}\)(参见这里)。然后,考虑一个状态\(dp[i]\)代表合成第\(i\)级武器的期望花费。显然\(dp[0] = a\)。

考虑\(dp[1]\)的求法,首先需要两个级别为\(0\)的武器,然后发现无论失败与否都可以保证至少又一个\(0\)级武器,所以我们只需要注意另外一个武器的花费就可以了:

\[ dp[1] = dp[0] + dp[1] \times \frac{1}{p} \]

也就是说,第一件武器的贡献在任何概率下都存在,即使失败也会至少存在一个武器;对于另外一件武器,考虑乘上它成功的次数就行了。

我们现在考虑\(i \geq 2\)的情况。首先,\(i – 2\)级别的武器永远存在,所以不需要乘系数,\(i – 1\)级别的武器锻造成功的次数也是\(\frac{1}{p}\),所以:

\[ dp[i] = dp[i – 1] * \frac{1}{p} + dp[i – 2] \]

这道题就没了,现在感觉有点傻逼。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// A.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1e7 + 20, mod = 998244353;
int b[MAX_N], c[MAX_N], n, a, bx, by, cx, cy, p, inv[MAX_N], max_range, dp[MAX_N];
int main()
{
freopen("forging.in", "r", stdin);
freopen("forging.out", "w", stdout);
scanf("%d%d%d%d%d%d%d", &n, &a, &bx, &by, &cx, &cy, &p);
b[0] = by + 1, max_range = max(max_range, b[0]);
c[0] = cy + 1, max_range = max(max_range, c[0]);
for (int i = 1; i < n; i++)
{
b[i] = ((long long)b[i - 1] * bx + by) % p + 1, max_range = max(max_range, b[i]);
c[i] = ((long long)c[i - 1] * cx + cy) % p + 1, max_range = max(max_range, c[i]);
}
inv[1] = 1;
for (int i = 2; i <= max_range; i++)
inv[i] = (long long)(mod - mod / i) * inv[mod % i] % mod;
dp[0] = a;
dp[1] = 1LL * (a + 1LL * inv[min(b[0], c[0])] * c[0] % mod * a % mod) % mod;
for (int i = 2; i <= n; i++)
dp[i] = (1LL * dp[i - 1] * inv[min(b[i - 2], c[i - 1])] % mod * c[i - 1] % mod + dp[i - 2]) % mod;
printf("%d", dp[n]);
return 0;
} // A.cpp
// A.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 1e7 + 20, mod = 998244353; int b[MAX_N], c[MAX_N], n, a, bx, by, cx, cy, p, inv[MAX_N], max_range, dp[MAX_N]; int main() { freopen("forging.in", "r", stdin); freopen("forging.out", "w", stdout); scanf("%d%d%d%d%d%d%d", &n, &a, &bx, &by, &cx, &cy, &p); b[0] = by + 1, max_range = max(max_range, b[0]); c[0] = cy + 1, max_range = max(max_range, c[0]); for (int i = 1; i < n; i++) { b[i] = ((long long)b[i - 1] * bx + by) % p + 1, max_range = max(max_range, b[i]); c[i] = ((long long)c[i - 1] * cx + cy) % p + 1, max_range = max(max_range, c[i]); } inv[1] = 1; for (int i = 2; i <= max_range; i++) inv[i] = (long long)(mod - mod / i) * inv[mod % i] % mod; dp[0] = a; dp[1] = 1LL * (a + 1LL * inv[min(b[0], c[0])] * c[0] % mod * a % mod) % mod; for (int i = 2; i <= n; i++) dp[i] = (1LL * dp[i - 1] * inv[min(b[i - 2], c[i - 1])] % mod * c[i - 1] % mod + dp[i - 2]) % mod; printf("%d", dp[n]); return 0; } // A.cpp
// A.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 1e7 + 20, mod = 998244353;

int b[MAX_N], c[MAX_N], n, a, bx, by, cx, cy, p, inv[MAX_N], max_range, dp[MAX_N];

int main()
{
    freopen("forging.in", "r", stdin);
    freopen("forging.out", "w", stdout);
    scanf("%d%d%d%d%d%d%d", &n, &a, &bx, &by, &cx, &cy, &p);
    b[0] = by + 1, max_range = max(max_range, b[0]);
    c[0] = cy + 1, max_range = max(max_range, c[0]);
    for (int i = 1; i < n; i++)
    {
        b[i] = ((long long)b[i - 1] * bx + by) % p + 1, max_range = max(max_range, b[i]);
        c[i] = ((long long)c[i - 1] * cx + cy) % p + 1, max_range = max(max_range, c[i]);
    }

    inv[1] = 1;
    for (int i = 2; i <= max_range; i++)
        inv[i] = (long long)(mod - mod / i) * inv[mod % i] % mod;

    dp[0] = a;
    dp[1] = 1LL * (a + 1LL * inv[min(b[0], c[0])] * c[0] % mod * a % mod) % mod;
    for (int i = 2; i <= n; i++)
        dp[i] = (1LL * dp[i - 1] * inv[min(b[i - 2], c[i - 1])] % mod * c[i - 1] % mod + dp[i - 2]) % mod;
    printf("%d", dp[n]);
    return 0;
} // A.cpp

B – Division 整除

他直接给了你\(n\)的单次质因子,所以会想到 CRT。考虑在各个素数域内进行线性筛来筛积性函数\(x^m\),然后统计\(x^m \equiv x \ (mod p_i)\)的个数,然后把答案乘起来就可以了。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// B.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 55, mod = 998244353;
int id, T, c, ci[MAX_N], m, func[12000], primes[12000];
bool isPrime[10001];
inline int read()
{
int s = 0, w = 1;
char ch = getchar();
while (ch < '0' || ch > '9')
{
if (ch == '-')
w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
s = s * 10 + ch - '0', ch = getchar();
return s * w;
}
inline int quick_pow(int bas, int tim, int modulo)
{
int ans = 1;
bas %= modulo;
while (tim)
{
if (tim & 1)
ans = 1LL * ans * bas % modulo;
bas = 1LL * bas * bas % modulo;
tim >>= 1;
}
return ans;
}
inline int sieve(int n)
{
int ans = 2;
for (register int i = 2; i <= n - 1; i++)
{
if (!isPrime[i])
func[i] = quick_pow(i, m, n);
for (register int j = 1; j <= n - 1; j++)
{
if (i * primes[j] > n)
break;
func[i * primes[j]] = func[i] * func[primes[j]] % n;
if (i % primes[j] == 0)
break;
}
ans += func[i] == i;
}
return ans;
}
int main()
{
/*
freopen("division.in", "r", stdin);
freopen("division.out", "w", stdout);
*/
int tot = 0;
for (register int i = 2; i <= 10000; i++)
{
if (!isPrime[i])
primes[++tot] = i;
for (register int j = 1; j <= tot; j++)
{
if (i * primes[j] > 10000)
break;
isPrime[i * primes[j]] = true;
if (i % primes[j] == 0)
break;
}
}
id = read(), T = read();
while (T--)
{
int ans = 1;
c = read(), m = read();
for (register int i = 1; i <= c; i++)
ci[i] = read(), ans = 1LL * ans * sieve(ci[i]) % mod;
printf("%d\n", ans);
}
return 0;
} // B.cpp
// B.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 55, mod = 998244353; int id, T, c, ci[MAX_N], m, func[12000], primes[12000]; bool isPrime[10001]; inline int read() { int s = 0, w = 1; char ch = getchar(); while (ch < '0' || ch > '9') { if (ch == '-') w = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar(); return s * w; } inline int quick_pow(int bas, int tim, int modulo) { int ans = 1; bas %= modulo; while (tim) { if (tim & 1) ans = 1LL * ans * bas % modulo; bas = 1LL * bas * bas % modulo; tim >>= 1; } return ans; } inline int sieve(int n) { int ans = 2; for (register int i = 2; i <= n - 1; i++) { if (!isPrime[i]) func[i] = quick_pow(i, m, n); for (register int j = 1; j <= n - 1; j++) { if (i * primes[j] > n) break; func[i * primes[j]] = func[i] * func[primes[j]] % n; if (i % primes[j] == 0) break; } ans += func[i] == i; } return ans; } int main() { /* freopen("division.in", "r", stdin); freopen("division.out", "w", stdout); */ int tot = 0; for (register int i = 2; i <= 10000; i++) { if (!isPrime[i]) primes[++tot] = i; for (register int j = 1; j <= tot; j++) { if (i * primes[j] > 10000) break; isPrime[i * primes[j]] = true; if (i % primes[j] == 0) break; } } id = read(), T = read(); while (T--) { int ans = 1; c = read(), m = read(); for (register int i = 1; i <= c; i++) ci[i] = read(), ans = 1LL * ans * sieve(ci[i]) % mod; printf("%d\n", ans); } return 0; } // B.cpp
// B.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 55, mod = 998244353;

int id, T, c, ci[MAX_N], m, func[12000], primes[12000];
bool isPrime[10001];

inline int read()
{
    int s = 0, w = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-')
            w = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
        s = s * 10 + ch - '0', ch = getchar();
    return s * w;
}

inline int quick_pow(int bas, int tim, int modulo)
{
    int ans = 1;
    bas %= modulo;
    while (tim)
    {
        if (tim & 1)
            ans = 1LL * ans * bas % modulo;
        bas = 1LL * bas * bas % modulo;
        tim >>= 1;
    }
    return ans;
}

inline int sieve(int n)
{
    int ans = 2;
    for (register int i = 2; i <= n - 1; i++)
    {
        if (!isPrime[i])
            func[i] = quick_pow(i, m, n);
        for (register int j = 1; j <= n - 1; j++)
        {
            if (i * primes[j] > n)
                break;
            func[i * primes[j]] = func[i] * func[primes[j]] % n;
            if (i % primes[j] == 0)
                break;
        }
        ans += func[i] == i;
    }
    return ans;
}

int main()
{
    /*
    freopen("division.in", "r", stdin);
    freopen("division.out", "w", stdout);
    */

    int tot = 0;
    for (register int i = 2; i <= 10000; i++)
    {
        if (!isPrime[i])
            primes[++tot] = i;
        for (register int j = 1; j <= tot; j++)
        {
            if (i * primes[j] > 10000)
                break;
            isPrime[i * primes[j]] = true;
            if (i % primes[j] == 0)
                break;
        }
    }

    id = read(), T = read();
    while (T--)
    {
        int ans = 1;
        c = read(), m = read();
        for (register int i = 1; i <= c; i++)
            ci[i] = read(), ans = 1LL * ans * sieve(ci[i]) % mod;
        printf("%d\n", ans);
    }
    return 0;
} // B.cpp

C – Money 欠钱

这道题大力 LCT 就行了。中间要注意只有深度严格单调的链才能被统计,且必须注意进行

split(x, y)
split(x, y)操作时要搞清楚这条链的朝向。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// C.cpp
#include <bits/stdc++.h>
#pragma GCC target("avx")
#pragma GCC optimize(2)
%:pragma GCC optimize(3)
%:pragma GCC optimize("Ofast")
#define lson ch[p][0]
#define rson ch[p][1]
using namespace std;
const int MAX_N = 1e5 + 200, INF = 0x3f3f3f3f;
int ch[MAX_N][2], fa[MAX_N], val[MAX_N], minVal[MAX_N], revTag[MAX_N];
int size[MAX_N], n, m, mem[MAX_N], sta[MAX_N];
#define rint register int
void write(int x){
if(x>9) write(x/10);
putchar(x%10+'0');
}
inline char nc()
{
static char buf[100001], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}
inline int read()
{
rint num = 0;
char c;
while (isspace(c = nc()))
;
while (num = num * 10 + c - 48, isdigit(c = nc()))
;
return num;
}
inline bool isRoot(rint p)
{
return ch[fa[p]][0] != p && ch[fa[p]][1] != p;
}
inline int check(rint p) { return ch[fa[p]][1] == p; }
inline void clear(rint p) { lson = rson = fa[p] = val[p] = size[p] = revTag[p] = minVal[p] = 0; }
inline void pushUp(rint p)
{
clear(0);
size[p] = 1 + size[lson] + size[rson];
minVal[p] = val[p];
if (lson)
minVal[p] = min(minVal[p], minVal[lson]);
if (rson)
minVal[p] = min(minVal[p], minVal[rson]);
}
inline void pushDown(rint p)
{
if (revTag[p])
{
if (lson)
revTag[lson] ^= 1, swap(ch[lson][0], ch[lson][1]);
if (rson)
revTag[rson] ^= 1, swap(ch[rson][0], ch[rson][1]);
revTag[p] = 0;
}
}
inline void update(rint x)
{
rint tot = 0;
sta[++tot] = x;
while (!isRoot(x))
x = fa[x], sta[++tot] = x;
while (tot)
pushDown(sta[tot--]);
}
inline void rotate(rint x)
{
rint y = fa[x], z = fa[y], dir = check(x), w = ch[x][dir ^ 1];
fa[x] = z;
if (!isRoot(y))
ch[z][check(y)] = x;
ch[y][dir] = w, fa[w] = y;
ch[x][dir ^ 1] = y, fa[y] = x;
pushUp(y), pushUp(x), pushUp(z);
}
inline void splay(rint x)
{
update(x);
for (rint fat = fa[x]; fat = fa[x], !isRoot(x); rotate(x))
if (!isRoot(fat))
rotate(check(fat) == check(x) ? fat : x);
}
inline int access(rint x)
{
rint fat = 0;
for (; x != 0; fat = x, x = fa[x])
splay(x), ch[x][1] = fat, pushUp(x);
return fat;
}
inline void makeRoot(rint p)
{
access(p), splay(p);
swap(lson, rson), revTag[p] ^= 1;
}
inline int find(rint p)
{
access(p), splay(p);
while (lson)
p = lson;
splay(p);
return p;
}
inline void link(rint x, rint y)
{
makeRoot(x);
if (find(y) == x)
return;
fa[x] = y;
}
inline void split(rint x, rint y)
{
makeRoot(x);
access(y), splay(y);
}
inline int lca(rint x, rint y)
{
access(x);
return access(y);
}
inline int findFa(rint x) { return mem[x] == x ? x : mem[x] = findFa(mem[x]); }
int main()
{
/*
freopen("money.in", "r", stdin);
freopen("money.out", "w", stdout);
*/
rint lastans = 0;
n = read(), m = read();
for (rint i = 1; i <= n; i++)
mem[i] = i, val[i] = minVal[i] = INF;
while (m--)
{
rint opt, a, b, c;
opt = read(), a = read(), b = read();
a = (a + lastans) % n + 1;
b = (b + lastans) % n + 1;
if (opt == 0)
{
c = read(), c = (c + lastans) % n + 1;
mem[findFa(a)] = findFa(b);
val[a] = minVal[a] = c;
link(a, b);
}
else
{
if (findFa(a) != findFa(b))
{
write(lastans = 0), puts("");
continue;
}
if (lca(a, b) == b)
{
rint root = findFa(b);
split(a, b);
write(lastans = minVal[ch[b][0]]), puts("");
makeRoot(root);
}
else
write(lastans = 0), puts("");
}
}
return 0;
}
// C.cpp #include <bits/stdc++.h> #pragma GCC target("avx") #pragma GCC optimize(2) %:pragma GCC optimize(3) %:pragma GCC optimize("Ofast") #define lson ch[p][0] #define rson ch[p][1] using namespace std; const int MAX_N = 1e5 + 200, INF = 0x3f3f3f3f; int ch[MAX_N][2], fa[MAX_N], val[MAX_N], minVal[MAX_N], revTag[MAX_N]; int size[MAX_N], n, m, mem[MAX_N], sta[MAX_N]; #define rint register int void write(int x){ if(x>9) write(x/10); putchar(x%10+'0'); } inline char nc() { static char buf[100001], *p1 = buf, *p2 = buf; return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++; } inline int read() { rint num = 0; char c; while (isspace(c = nc())) ; while (num = num * 10 + c - 48, isdigit(c = nc())) ; return num; } inline bool isRoot(rint p) { return ch[fa[p]][0] != p && ch[fa[p]][1] != p; } inline int check(rint p) { return ch[fa[p]][1] == p; } inline void clear(rint p) { lson = rson = fa[p] = val[p] = size[p] = revTag[p] = minVal[p] = 0; } inline void pushUp(rint p) { clear(0); size[p] = 1 + size[lson] + size[rson]; minVal[p] = val[p]; if (lson) minVal[p] = min(minVal[p], minVal[lson]); if (rson) minVal[p] = min(minVal[p], minVal[rson]); } inline void pushDown(rint p) { if (revTag[p]) { if (lson) revTag[lson] ^= 1, swap(ch[lson][0], ch[lson][1]); if (rson) revTag[rson] ^= 1, swap(ch[rson][0], ch[rson][1]); revTag[p] = 0; } } inline void update(rint x) { rint tot = 0; sta[++tot] = x; while (!isRoot(x)) x = fa[x], sta[++tot] = x; while (tot) pushDown(sta[tot--]); } inline void rotate(rint x) { rint y = fa[x], z = fa[y], dir = check(x), w = ch[x][dir ^ 1]; fa[x] = z; if (!isRoot(y)) ch[z][check(y)] = x; ch[y][dir] = w, fa[w] = y; ch[x][dir ^ 1] = y, fa[y] = x; pushUp(y), pushUp(x), pushUp(z); } inline void splay(rint x) { update(x); for (rint fat = fa[x]; fat = fa[x], !isRoot(x); rotate(x)) if (!isRoot(fat)) rotate(check(fat) == check(x) ? fat : x); } inline int access(rint x) { rint fat = 0; for (; x != 0; fat = x, x = fa[x]) splay(x), ch[x][1] = fat, pushUp(x); return fat; } inline void makeRoot(rint p) { access(p), splay(p); swap(lson, rson), revTag[p] ^= 1; } inline int find(rint p) { access(p), splay(p); while (lson) p = lson; splay(p); return p; } inline void link(rint x, rint y) { makeRoot(x); if (find(y) == x) return; fa[x] = y; } inline void split(rint x, rint y) { makeRoot(x); access(y), splay(y); } inline int lca(rint x, rint y) { access(x); return access(y); } inline int findFa(rint x) { return mem[x] == x ? x : mem[x] = findFa(mem[x]); } int main() { /* freopen("money.in", "r", stdin); freopen("money.out", "w", stdout); */ rint lastans = 0; n = read(), m = read(); for (rint i = 1; i <= n; i++) mem[i] = i, val[i] = minVal[i] = INF; while (m--) { rint opt, a, b, c; opt = read(), a = read(), b = read(); a = (a + lastans) % n + 1; b = (b + lastans) % n + 1; if (opt == 0) { c = read(), c = (c + lastans) % n + 1; mem[findFa(a)] = findFa(b); val[a] = minVal[a] = c; link(a, b); } else { if (findFa(a) != findFa(b)) { write(lastans = 0), puts(""); continue; } if (lca(a, b) == b) { rint root = findFa(b); split(a, b); write(lastans = minVal[ch[b][0]]), puts(""); makeRoot(root); } else write(lastans = 0), puts(""); } } return 0; }
// C.cpp
#include <bits/stdc++.h>
#pragma GCC target("avx")
#pragma GCC optimize(2)
%:pragma GCC optimize(3)
%:pragma GCC optimize("Ofast")
#define lson ch[p][0]
#define rson ch[p][1]

using namespace std;

const int MAX_N = 1e5 + 200, INF = 0x3f3f3f3f;

int ch[MAX_N][2], fa[MAX_N], val[MAX_N], minVal[MAX_N], revTag[MAX_N];
int size[MAX_N], n, m, mem[MAX_N], sta[MAX_N];

#define rint register int

void write(int x){
    if(x>9) write(x/10);
    putchar(x%10+'0');
}

inline char nc()
{
    static char buf[100001], *p1 = buf, *p2 = buf;
    return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}

inline int read()
{
    rint num = 0;
    char c;
    while (isspace(c = nc()))
        ;
    while (num = num * 10 + c - 48, isdigit(c = nc()))
        ;
    return num;
}

inline bool isRoot(rint p)
{
    return ch[fa[p]][0] != p && ch[fa[p]][1] != p;
}

inline int check(rint p) { return ch[fa[p]][1] == p; }

inline void clear(rint p) { lson = rson = fa[p] = val[p] = size[p] = revTag[p] = minVal[p] = 0; }

inline void pushUp(rint p)
{
    clear(0);
    size[p] = 1 + size[lson] + size[rson];
    minVal[p] = val[p];
    if (lson)
        minVal[p] = min(minVal[p], minVal[lson]);
    if (rson)
        minVal[p] = min(minVal[p], minVal[rson]);
}

inline void pushDown(rint p)
{
    if (revTag[p])
    {
        if (lson)
            revTag[lson] ^= 1, swap(ch[lson][0], ch[lson][1]);
        if (rson)
            revTag[rson] ^= 1, swap(ch[rson][0], ch[rson][1]);
        revTag[p] = 0;
    }
}

inline void update(rint x)
{
    rint tot = 0;
    sta[++tot] = x;
    while (!isRoot(x))
        x = fa[x], sta[++tot] = x;
    while (tot)
        pushDown(sta[tot--]);
}

inline void rotate(rint x)
{
    rint y = fa[x], z = fa[y], dir = check(x), w = ch[x][dir ^ 1];
    fa[x] = z;
    if (!isRoot(y))
        ch[z][check(y)] = x;
    ch[y][dir] = w, fa[w] = y;
    ch[x][dir ^ 1] = y, fa[y] = x;
    pushUp(y), pushUp(x), pushUp(z);
}

inline void splay(rint x)
{
    update(x);
    for (rint fat = fa[x]; fat = fa[x], !isRoot(x); rotate(x))
        if (!isRoot(fat))
            rotate(check(fat) == check(x) ? fat : x);
}

inline int access(rint x)
{
    rint fat = 0;
    for (; x != 0; fat = x, x = fa[x])
        splay(x), ch[x][1] = fat, pushUp(x);
    return fat;
}

inline void makeRoot(rint p)
{
    access(p), splay(p);
    swap(lson, rson), revTag[p] ^= 1;
}

inline int find(rint p)
{
    access(p), splay(p);
    while (lson)
        p = lson;
    splay(p);
    return p;
}

inline void link(rint x, rint y)
{
    makeRoot(x);
    if (find(y) == x)
        return;
    fa[x] = y;
}

inline void split(rint x, rint y)
{
    makeRoot(x);
    access(y), splay(y);
}

inline int lca(rint x, rint y)
{
    access(x);
    return access(y);
}

inline int findFa(rint x) { return mem[x] == x ? x : mem[x] = findFa(mem[x]); }

int main()
{
    /*
    freopen("money.in", "r", stdin);
    freopen("money.out", "w", stdout);
    */

    rint lastans = 0;
    n = read(), m = read();
    for (rint i = 1; i <= n; i++)
        mem[i] = i, val[i] = minVal[i] = INF;
    while (m--)
    {
        rint opt, a, b, c;
        opt = read(), a = read(), b = read();
        a = (a + lastans) % n + 1;
        b = (b + lastans) % n + 1;
        if (opt == 0)
        {
            c = read(), c = (c + lastans) % n + 1;
            mem[findFa(a)] = findFa(b);
            val[a] = minVal[a] = c;
            link(a, b);
        }
        else
        {
            if (findFa(a) != findFa(b))
            {
                write(lastans = 0), puts("");
                continue;
            }
            if (lca(a, b) == b)
            {
                rint root = findFa(b);
                split(a, b);
                write(lastans = minVal[ch[b][0]]), puts("");
                makeRoot(root);
            }
            else
                write(lastans = 0), puts("");
        }
    }
    return 0;
}

 

Leave a Reply

Your email address will not be published. Required fields are marked *