効果の対象に
右のそれ以外の場合は、出力父親に息子を求めて最小のクエリ・チェーンの端に根ざした木でもダイナミックエッジ、\(0 \) 。
力によって、\(N- \ 1当量5 ^ 10 \) 、オペランド\(m個の\ 1当量6〜10 ^ \) 、複数のエッジが存在することになります。
分析
一つのアプローチは、エッジもれる((B)\ \の ) 暴力を変更するとき\(\)の全ての点の乗算器アレイサブツリーを、その後、要求されたときの回答の配列を乗じて計算しました。
明らかに、各変形関連暴力の点である\(O(N)\)レベルは、変形の複雑さである\(O(N ^ 2logn)\) 。
通信ブロックサイズ、回数に接続された、より大きな通信ブロックから小さいサイズのヒューリスティック合力が各時点が変更された場合暴力\(O(LOGN)\)回、各回の変形がある\ (O(LOGN)\)複雑さを低減する修飾の複雑\(O(nlog ^ 2N)\) 。
あなたが尋ねられたとき、木の父親方向を変えることを余儀なくされているので(\(U、V)) \ 時間、\(U \)に(LCAの\)\のパスのすべての側面元の方向と木の父向きが一致している(注:父方向)が父親に息子からの方向を指し、\ (V \)する(LCAの\)\へのパス上のすべてのエッジの元の方向とツリーの父親方向から元のツリーように、反対の\(uが\)する\します(V \) 。次いで以上が存在する場合、それぞれ、二つの配列を維持するために倍増元の方向との父方向同じ側に存在する場合、元の方向と父親方向反対側の縁部は、この問題を取得するために、接続されていないこの場合、2つの点に注意を払います。
時間複雑\(O(nlog 2N + mlogn ^)\) 、定数に注意を払います。
コード
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100007;
inline int read()
{
int x = 0, f = 0;
char c = getchar();
for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = 1;
for (; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ '0');
return f ? -x : x;
}
inline int min(int a, int b)
{
if (a < b) return a;
return b;
}
int n, m, fa[N], size[N];
int opt, a, b, c, lastans, flag, ta, tb;
int tot, h, t, st[N], to[N << 1], nx[N << 1], dir[N << 1], val[N << 1], q[N];
void add(int u, int v, int w, int c) { to[++tot] = v, nx[tot] = st[u], dir[tot] = w, val[tot] = c, st[u] = tot; }
int anc[N][17], mi[N][17], tag[2][N][17], dep[N];
inline int getfa(int x) { return fa[x] == x ? x : getfa(fa[x]); }
int getans(int u, int v)
{
int f = 0, ans = 0x3f3f3f3f;
if (dep[u] < dep[v]) swap(u, v), f ^= 1;
for (int i = 16; i >= 0; --i) if (dep[anc[u][i]] >= dep[v])
{
if (tag[f][u][i]) return 0;
ans = min(ans, mi[u][i]), u = anc[u][i];
}
if (u == v) return ans;
for (int i = 16; i >= 0; --i) if (anc[u][i] != anc[v][i])
{
if (tag[f][u][i] || tag[!f][v][i]) return 0;
ans = min(ans, min(mi[u][i], mi[v][i])), u = anc[u][i], v = anc[v][i];
}
if (!anc[u][0] && !anc[v][0]) return 0;
if (tag[f][u][0] || tag[!f][v][0]) return 0;
ans = min(ans, min(mi[u][0], mi[v][0]));
return ans;
}
int main()
{
//freopen("money.in", "r", stdin);
//freopen("money.out", "w", stdout);
n = read(), m = read();
for (int i = 1; i <= n; ++i) fa[i] = i, size[i] = 1, dep[i] = 1;
for (int i = 1; i <= m; ++i)
{
opt = read();
if (opt)
{
a = read(), b = read(), a = (a + lastans) % n + 1, b = (b + lastans) % n + 1;
printf("%d\n", lastans = getans(a, b));
}
else
{
a = read(), b = read(), c = read(), a = (a + lastans) % n + 1, b = (b + lastans) % n + 1, c = (c + lastans) % n + 1, flag = 0, ta = a, tb = b;
add(b, a, 0, c), add(a, b, 1, c);
ta = getfa(a), tb = getfa(b);
if (size[ta] > size[tb]) swap(a, b), swap(ta, tb), flag ^= 1;
fa[ta] = tb, size[tb] += size[ta], anc[a][0] = b, mi[a][0] = c, tag[0][a][0] = flag, tag[1][a][0] = !flag, dep[a] = dep[b] + 1;
h = 1, q[t = 1] = a;
while (h <= t)
{
int u = q[h]; ++h;
for (int i = 1; i <= 16; ++i)
{
anc[u][i] = anc[anc[u][i - 1]][i - 1];
mi[u][i] = min(mi[u][i - 1], mi[anc[u][i - 1]][i - 1]);
tag[0][u][i] = (tag[0][u][i - 1] | tag[0][anc[u][i - 1]][i - 1]);
tag[1][u][i] = (tag[1][u][i - 1] | tag[1][anc[u][i - 1]][i - 1]);
}
for (int i = st[u]; i; i = nx[i])
if (to[i] != anc[u][0])
anc[to[i]][0] = u, mi[to[i]][0] = val[i], tag[0][to[i]][0] = dir[i], tag[1][to[i]][0] = !dir[i], dep[to[i]] = dep[u] + 1, q[++t] = to[i];
}
}
}
return 0;
}