省选 考前模板
线性筛的通用情况
转载自 自为风月马前卒的博客
//low[x]:x的最小质因子的次幂
vis[1] = low[1] = 1; H[1] = 初始化;
for(int i = 2; i <= N; i++)
{
if(!vis[i]) prime[++tot] = i, mu[i] = -1, H[i] = 质数的情况, low[i] = i;
for(int j = 1; j <= tot && i * prime[j] <= N; j++)
{
vis[i * prime[j]] = 1;
if(!(i % prime[j]))
{
low[i * prime[j]] = (low[i] * prime[j]);
if(low[i] == i) H[i * prime[j]] = 特殊判断;
else H[i * prime[j]] = H[i / low[i]] * H[prime[j] * low[i]];
break;
}
H[i * prime[j]] = H[i] * H[prime[j]];
low[i * prime[j]] = prime[j];
}
}
KMP字符串匹配
int k = 0; nt[1] = 0;
for (int i = 2; i <= lenb; ++i)
{
while (k && b[k + 1] != b[i])k = nt[k];
if (b[k + 1] == b[i])++k;
nt[i] = k;
}
k = 0;
for (int i = 1; i <= lena; ++i)
{
while (k && b[k + 1] != a[i])k = nt[k];
if (b[k + 1] == a[i])++k;
if (k == lenb)pos[++ans] = i - lenb + 1;
}
manacher/马拉车 回文
scanf("%s", s + 1); n = strlen(s + 1);
for (int i = 1, j = 0; i <= n; ++i)t[++j] = '*', t[++j] = s[i]; t[n + n + 1] = '*';
t[0] = '$'; n = n + n + 1;
for (int i = 1; i <= n; ++i)
{
p[i] = r > i ? min(r - i, p[2 * pos - i]) : 0;
while (t[i - p[i] - 1] == t[i + p[i] + 1])++p[i];
if (i + p[i] > r)r = i + p[i], pos = i;
}
PAM
int cnt = 1, last, em;
int get_fail(int x)
{
while (s[em - len[x] - 1] != s[em])x = fail[x];
return x;
}
int get_nt(int x)
{
while (s[em - len[x] - 1] != s[em] || ((len[x] + 2) << 1) > len[cnt])x = fail[x];
return x;
}
void Insert(int x)
{
int f1 = get_fail(last);
if (!tr[f1][x])
{
len[++cnt] = len[f1] + 2;
fail[cnt] = tr[get_fail(fail[f1])][x];
if (len[cnt] <= 2)nt[cnt] = fail[cnt];
else nt[cnt] = tr[get_nt(nt[f1])][x];
tr[f1][x] = cnt;
}
last = tr[f1][x];
}
fail[0] = 1; fail[1] = 0; len[0] = 0; len[1] = -1;
for (int i = 1; i <= n; ++i)em = i, Insert(s[i] - 'a');
AC 自动机
void build(string s)
{
int l = s.length(), now = 0;
for (int i = 0; i < l; ++i)
{
if (!AC[now].vis[s[i] - 'a'])AC[now].vis[s[i] - 'a'] = ++cnt;
now = AC[now].vis[s[i] - 'a'];
}
++AC[now].end;
}
queue<int>q;
void Gfail()
{
int u;
for (int i = 0; i < 26; ++i)
if (AC[0].vis[i]) AC[AC[0].vis[i]].fail = 0, q.push(AC[0].vis[i]);
while (!q.empty())
{
u = q.front(); q.pop();
for (int i = 0; i < 26; ++i)
if (AC[u].vis[i])
{
AC[AC[u].vis[i]].fail = AC[AC[u].fail].vis[i];
q.push(AC[u].vis[i]);
} else AC[u].vis[i] = AC[AC[u].fail].vis[i];
}
}
匈牙利二分图最大匹配
bool dfs(int x)
{
for (int i = head[x]; i; i = e[i].nt)
{
if (vis[e[i].to])continue;
vis[e[i].to] = 1;
if (!mch[e[i].to] || dfs(mch[e[i].to]))
{
mch[e[i].to] = x;
return 1;
}
}
return 0;
}
for (int i = 1; i <= n; ++i)
{
memset(vis, 0, sizeof(vis));
if (dfs(i))++ans;
}
网络最大流
tot = 1;
int bfs()
{
int x;
memset(dis, 0, sizeof(dis));
while (!q.empty())q.pop();
for (int i = 1; i <= n; ++i)cur[i] = head[i];
dis[s] = 1; q.push(s);
while (!q.empty())
{
x = q.front(); q.pop();
for (int i = head[x]; i; i = nt[i])
if (val[i] && !dis[to[i]])
{
dis[to[i]] = dis[x] + 1;
if (to[i] == t)return 1;
q.push(to[i]);
}
}
return 0;
}
int dinic(int x, int flow)
{
if (x == t || !flow)return flow;
int k, res = flow;
for (int &i = cur[x]; i; i = nt[i])
if (val[i] && dis[to[i]] == dis[x] + 1)
{
k = dinic(to[i], min(val[i], res));
if (!k)dis[to[i]] = 0;
val[i] -= k; val[i ^ 1] += k;
if (!(res -= k))break;
}
return flow - res;
}
while (bfs())ans += dinic(s, inf);
最小费用最大流
tot = 1;
int SPFA()
{
int x;
memset(dis, 0x3f, sizeof(dis));
memset(pre, -1, sizeof(pre));
dis[s] = 0; q.push(s); vis[s] = 1;
while (!q.empty())
{
x = q.front(); q.pop(); vis[x] = 0;
for (int i = head[x]; i; i = nt[i])
if (val[i] && dis[to[i]] > dis[x] + cost[i])
{
dis[to[i]] = dis[x] + cost[i]; pre[to[i]] = i; from[to[i]] = x;
if (!vis[to[i]])q.push(to[i]), vis[to[i]] = 1;
}
}
return pre[t] != -1;
}
void MFMC()
{
int k;
while (SPFA())
{
k = inf;
for (int i = t; i != s; i = from[i])k = min(k, val[pre[i]]);
ans1 += k; ans2 += dis[t] * k;
for (int i = t; i != s; i = from[i])val[pre[i]] -= k, val[pre[i] ^ 1] += k;
}
}
无源汇有上下界可行流
int main()
{
cin >> n >> m;
S = 0; T = n + 1;
for (int i = 1; i <= m; ++i)
{
x = read(); y = read(); L[i] = read(); r = read();
ADD(x, y, r - L[i]);
A[x] -= L[i]; A[y] += L[i];
c[i] = tot;
}
for (int i = 1; i <= n; ++i)
if (A[i] > 0)ADD(S, i, A[i]), sum += A[i];
else if (A[i])ADD(i, T, -A[i]);
while (bfs(S, T))
while (flow = dinic(S, inf))ans += flow;
if (ans != sum)return puts("NO") == 23333;
puts("YES");
for (int i = 1; i <= m; ++i)Write(L[i] + e[c[i]].cap, 1), putchar('\n');
return 0;
}
有源汇有上下界最大流
int main()
{
cin >> n >> m >> S >> T;
SS = 0; TT = n + 1;
for (int i = 1; i <= m; ++i)
{
x = read(); y = read(); l = read(); r = read();
ADD(x, y, r - l);
A[x] -= l; A[y] += l;
}
for (int i = 1; i <= n; ++i)
if (A[i] > 0) {ADD(SS, i, A[i]); sum += A[i];}
else if (A[i])ADD(i, TT, -A[i]);
ADD(T, S, inf);
while (bfs(SS, TT))while (flow = dinic(SS, inf, TT))ans += flow;
if (ans != sum)return puts("please go home to sleep") == 23333;
ans = 0;
while (bfs(S, T))while (flow = dinic(S, inf, T))ans += flow;
cout << ans;
return 0;
}
有源汇有上下界最小流
int main()
{
cin >> n >> m >> S >> T;
SS = 0; TT = n + 1;
for (int i = 1; i <= m; ++i)
{
x = read(); y = read(); l = read(); r = read();
ADD(x, y, r - l);
A[x] -= l; A[y] += l;
}
for (int i = 1; i <= n; ++i)
if (A[i] > 0) {ADD(SS, i, A[i]); sum += A[i];}
else if (A[i])ADD(i, TT, -A[i]);
while (bfs(SS, TT))while (flow = dinic(SS, inf, TT))ans += flow;
ADD(T, S, inf);
while (bfs(SS, TT))while (flow = dinic(SS, inf, TT))ans += flow;
if (ans != sum)return puts("please go home to sleep") == 23333;
cout << e[tot].cap;
return 0;
}
左偏树(可并堆)
struct dui {int val, fa, dis, ch[2];} tr[N << 1];
int find(int x) {return x == tr[x].fa ? tr[x].fa : tr[x].fa = find(tr[x].fa);}
int Merge(int x, int y)
{
if (!x || !y)return x + y;
if (tr[x].val > tr[y].val || (tr[x].val == tr[y].val && x > y))swap(x, y);
tr[x].ch[1] = Merge(tr[x].ch[1], y); tr[tr[x].ch[1]].fa = x;
if (tr[tr[x].ch[0]].dis < tr[tr[x].ch[1]].dis)swap(tr[x].ch[0], tr[x].ch[1]);
tr[x].dis = tr[tr[x].ch[1]].dis + 1;
return x;
}
void Delete(int x)
{
tr[x].val = -1;
tr[tr[x].ch[0]].fa = tr[x].ch[0]; tr[tr[x].ch[1]].fa = tr[x].ch[1];
tr[x].fa = Merge(tr[x].ch[0], tr[x].ch[1]);
}
圆方树
void Tarjan(int x)
{
dfn[x] = low[x] = ++cnt; zhan[++Top] = x;
for (int i = Head[x]; i; i = Nt[i])
if (!dfn[To[i]])
{
Tarjan(To[i]); low[x] = min(low[x], low[To[i]]);
if (low[To[i]] >= dfn[x])
{
add(++num, x); add(x, num);
int t;
do
{
t = zhan[Top--]; add(num, t); add(t, num);
} while (t != To[i]);
}
}
else low[x] = min(low[x], dfn[To[i]]);
}
虚树
int my(int a, int b) {return dfn[a] < dfn[b];}
void build()
{
int x, lca;
sort(a + 1, a + 1 + k, my);
if (a[1] != 1)zhan[top = 1] = 1;
for (int i = 1; i <= k; ++i)
{
x = a[i];
if (top <= 1) {zhan[++top] = x; continue;}
lca = LCA(zhan[top], x);
if (lca == zhan[top]) {zhan[++top] = x; continue;}
while (top > 1 && dep[lca] <= dep[zhan[top - 1]]) {add(zhan[top - 1], zhan[top], 0); --top;}
if (lca != zhan[top])add(lca, zhan[top], 0), zhan[top] = lca;
zhan[++top] = x;
}
while (top) {add(zhan[top - 1], zhan[top], 0); top--;}
}
dsu on tree
void ADD(int x, int fa, int val)
{
cnt[col[x]] += val;
if (cnt[col[x]] > mx)mx = cnt[col[x]], nowans = col[x];
else if (cnt[col[x]] == mx)nowans += col[x];
for (int i = head[x]; i; i = nt[i])
if (to[i] != fa && to[i] != Son)ADD(to[i], x, val);
}
void dfs2(int x, int fa, int opt)
{
for (int i = head[x]; i; i = nt[i])
if (to[i] != fa && to[i] != son[x])dfs2(to[i], x, 0);
if (son[x])dfs2(son[x], x, 1), Son = son[x];
ADD(x, fa, 1); Son = 0; ans[x] = nowans;
if (!opt)ADD(x, fa, -1), nowans = 0, mx = 0;
}
Tarjan求割边
void Tarjan(int x, int f)
{
dfn[x] = low[x] = ++dfn_id;
for (int i = head[x]; i; i = nt[i])
if (i != f)
{
if (!dfn[to[i]])
{
Tarjan(to[i], i ^ 1), low[x] = min(low[x], low[to[i]]);
if (low[to[i]] > dfn[x])vis[i] = vis[i ^ 1] = 1;
} else low[x] = min(low[x], dfn[to[i]]);
}
}
Tarjan求割点
void Tarjan(int x, int rt)
{
int er = 0;
dfn[x] = low[x] = ++cnt;
for (int i = head[x]; i; i = e[i].nt)
{
int v = e[i].to;
if (!dfn[e[i].to])
{
Tarjan(v, rt);
low[x] = min(low[x], low[v]);
if (low[v] >= dfn[x] && x != rt)cut[x] = 1;
if (x == rt)er++;
}
else low[x] = min(low[x], dfn[v]);
}
if (x == rt && er > 1)cut[x] = 1;
}
NTT
void NTT(LL *A, int lim, int opt)
{
for (int i = 0; i < lim; ++i)r[i] = (r[i >> 1] >> 1) | ((i & 1) ? (lim >> 1) : 0);
for (int i = 0; i < lim; ++i)if (i < r[i])swap(A[i], A[r[i]]);
LL w, wn, x, y;
for (int mid = 1, len = 2; len <= lim; mid <<= 1, len <<= 1)
{
wn = ksm(opt == 1 ? G : Ginv, (mod - 1) / len, mod);
for (int j = 0; j < lim; j += len)
{
w = 1;
for (int k = j; k < j + mid; ++k, w = w * wn % mod)
{
x = A[k]; y = A[k + mid] * w % mod;
A[k] = (x + y) % mod; A[k + mid] = (x - y + mod) % mod;
}
}
}
if (opt == 1)return;
int ni = ksm(lim, mod - 2, mod);
for (int i = 0; i < lim; ++i)A[i] = A[i] * ni % mod;
}
FFT
void FFT(xu *A, int lim, int opt)
{
for (int i = 0; i < lim; ++i)r[i] = (r[i >> 1] >> 1) | (i & 1 ? (lim >> 1) : 0);
for (int i = 0; i < lim; ++i)if (i < r[i])swap(A[i], A[r[i]]);
for (int mid = 1; mid < lim; mid <<= 1)
{
xu wn(cos(PI / mid), opt * sin(PI / mid));
for (int len = mid << 1, j = 0; j < lim; j += len)
{
xu w((DB)1, (DB)0);
for (int k = j; k < mid + j; ++k, w = w * wn)
{
xu a = A[k], b = w * A[k + mid];
A[k] = a + b;
A[k + mid] = a - b;
}
}
}
if (opt == 1)return;
for (int i = 0; i < lim; ++i)A[i] = xu(A[i].x / lim , 0);
}
分治NTT
void solve(int l, int r)
{
if (l == r)return;
int mid = (l + r) >> 1, len = r - l + 1;
solve(l, mid);
for (int i = 0; i < len; ++i)a[i] = b[i] = 0;
for (int i = l; i <= mid; ++i)a[i - l] = f[i]; for (int i = 1; l + i <= r; ++i)b[i] = g[i];
NTT(a, len, 1); NTT(b, len, 1);
for (int i = 0; i < len; ++i)a[i] = (LL)a[i] * b[i] % mod;
NTT(a, len, -1);
for (int i = mid + 1; i <= r; ++i)(f[i] += a[i - l]) %= mod;
solve(mid + 1, r);
}
多项式 INV LN EXP
求逆:\(B \equiv 2B_0 -AB_0^2\)
求ln:\(\displaystyle \int \frac{A'}{A}\)
求exp:\(B \equiv B_0(1-lnB_0+A)\)
void INV(int siz, LL *A, LL *B)
{
if (siz == 1)
{
B[0] = ksm(A[0], mod - 2, mod);
return;
}
INV((siz + 1) >> 1, A, B);
int lim = 1;
while (lim < (siz << 1))lim <<= 1;
for (int i = 0; i < siz; ++i)c[i] = A[i];
for (int i = siz; i < lim; ++i)c[i] = 0;
NTT(c, lim, 1); NTT(B, lim, 1);
for (int i = 0; i < lim; ++i)B[i] = B[i] * (2 - c[i] * B[i] % mod + mod) % mod;
NTT(B, lim, -1);
for (int i = siz; i < lim; ++i)B[i] = 0;
}
void MUL(LL *A, int n, LL *B, int m)
{
int lim = 1;
while (lim <= (n + m))lim <<= 1;
NTT(A, lim, 1); NTT(B, lim, 1);
for (int i = 0; i < lim; ++i)A[i] = A[i] * B[i] % mod;
NTT(A, lim, -1);
}
LL LN_inv[N];
void LN(int n, LL *A, LL *B)
{
int lim = 1;
while (lim <= (n << 1))lim <<= 1;
for (int i = 1; i < n; ++i)B[i - 1] = A[i] * i % mod;
for (int i = n - 1; i < lim; ++i)B[i] = 0;
for (int i = 0; i < lim; ++i)LN_inv[i] = 0;
INV(n, A, LN_inv);
MUL(B, n, LN_inv, n);
for (int i = lim - 1; i >= 1; --i)B[i] = B[i - 1] * ksm(i, mod - 2, mod);
B[0] = 0;
}
LL ln[N];
void EXP(int siz, LL *A, LL *B)
{
if (siz == 1)
{
B[0] = 1;
return;
}
EXP((siz + 1) >> 1, A, B);
LN(siz, B, ln);
int lim = 1;
while (lim < (siz << 1))lim <<= 1;
for (int i = 0; i < siz; ++i)ln[i] = A[i] - ln[i];
ln[0]++;
for (int i = siz; i < lim; ++i)ln[i] = B[i] = 0;
MUL(B, siz, ln, siz);
}
FWT
void GET()
{
for(int i=0;i<n;++i)a[i]=(LL)a[i]*b[i]%mod;
}
void OR(LL *A, int opt)
{
for (int mid = 1, len = 2; len <= n; mid <<= 1, len <<= 1)
for (int i = 0; i < n; i += len)
for (int j = i; j < i + mid; ++j)
(A[j + mid] += A[j] * opt) %= mod;
}
void AND(LL *A, int opt)
{
for (int mid = 1, len = 2; len <= n; mid <<= 1, len <<= 1)
for (int i = 0; i < n; i += len)
for (int j = i; j < i + mid; ++j)
(A[j] += A[j + mid] * opt) %= mod;
}
void XOR(LL *A, int opt)
{
int a, b;
for (int mid = 1, len = 2; len <= n; mid <<= 1, len <<= 1)
for (int i = 0; i < n; i += len)
for (int j = i; j < i + mid; ++j)
a = A[j], b = A[j + mid], A[j] = (LL)(a + b) * opt % mod, A[j + mid] = (LL)(a - b) * opt % mod;
}
OR(a, 1); OR(b, 1); GET(); OR(a, mod - 1);
AND(a, 1); AND(b, 1); GET(); AND(a, mod - 1);
XOR(a, 1); XOR(b, 1); GET(); XOR(a, (mod + 1) / 2);
子集卷积
inline int yi(int x) {int res = 0; while (x)res += x & 1, x >>= 1; return res;}
void OR(int *A, int lim, int opt)
{
for (int mid = 1, len = 2; len <= lim; mid <<= 1, len <<= 1)
for (int j = 0; j < lim; j += len)
for (int k = j; k < j + mid; ++k)
(A[k + mid] += A[k] * opt) %= mod;
}
int main()
{
cin >> m; n = 1 << m;
for (int i = 0; i < n; ++i)scanf("%d", &a[yi(i)][i]);
for (int i = 0; i < n; ++i)scanf("%d", &b[yi(i)][i]);
for (int i = 0; i <= m; ++i)OR(a[i], n, 1), OR(b[i], n, 1);
for (int i = 0; i < n; ++i)
for (int j = 0; j <= m; ++j)
for (int k = 0; k <= j; ++k)c[j][i] = ((LL)c[j][i] + (LL)a[k][i] * b[j - k][i]) % mod;
for (int i = 0; i <= m; ++i)OR(c[i], n, -1);
for (int i = 0; i < n; ++i)printf("%d ", (c[yi(i)][i] + mod) % mod);
return 0;
}
自适应辛普森
辛普森公式:\(\displaystyle \int_{a}^{b}f(x)dx \approx \frac{(b-a)(f(a)+f(b)+4f(\frac{a+b}{2}))}{6}\)
inline DB simpson(DB l , DB r) {return (f(l) + 4 * f((l + r) / 2) + f(r)) * (r - l) / 6;}
inline DB jue(DB x) {return x > 0 ? x : -x;}
DB asr(DB l, DB r, DB eps, DB ans)
{
DB mid = (l + r) / 2, L = simpson(l, mid), R = simpson(mid, r);
if (jue(L + R - ans) <= eps * 15)return L + R + (L + R - ans) / 15;
return asr(l, mid, eps / 2, L) + asr(mid, r, eps / 2, R);
}
Matrix-Tree 定理(矩阵树定理)
for (int i = 2, inv, tmp; i <= n; ++i)
{
for (int j = i + 1; j <= n; ++j)
if (!a[i][i] && a[j][i]) {ans = -ans; swap(a[i], a[j]); break;}
inv = ksm(a[i][i], mod - 2, mod);
for (int j = i + 1; j <= n; ++j)
{
tmp = (LL)a[j][i] * inv % mod;
for (int k = i; k <= n; ++k)a[j][k] = (a[j][k] - (LL)a[i][k] * tmp % mod) % mod;
}
}
二维凸包
inline int my1(dian a, dian b) {return a.x == b.x ? a.y < b.y : a.x < b.x;}
inline int my2(dian a, dian b)
{
int tmp = dump(cross(a - e[1], b - e[1]));
if (tmp > 0)return 1;
else if (tmp == 0 && dump(dis(a, e[1]) - dis(b, e[1])) < 0)return 1;
return 0;
}
inline void TU_BAO()
{
sort(e + 1, e + 1 + n, my1);
sort(e + 2, e + 1 + n, my2);
zhan[top = 1] = e[1];
for (int i = 2; i <= n; ++i)
{
while (top > 1 && dump(cross(e[i] - zhan[top - 1], zhan[top] - zhan[top - 1])) >= 0)--top;
zhan[++top] = e[i];
}
}
半平面交
friend bool operator <(const xian &a, const xian &b) {return a.ang < b.ang;}
DB cross(dian a, dian b) {return a.x * b.y - a.y * b.x;}
int onleft(xian s, dian a) {return cross(s.v, a - s.p) > 0;}
dian linemeet(xian a, xian b) {return a.p + a.v * (cross(b.v, a.p - b.p) / cross(a.v, b.v));}
int hpi(xian *L, int n)
{
sort(L + 1, L + 1 + n);
int head, tail;
sta[head = tail = 1] = L[1];
for (int i = 2; i <= n; ++i)
{
while (head < tail && !onleft(L[i], p[tail - 1]))tail--;
while (head < tail && !onleft(L[i], p[head]))head++;
sta[++tail] = L[i];
if (!dump(cross(sta[tail].v, sta[tail - 1].v)))
{
tail--;
if (onleft(sta[tail], L[i].p))sta[tail] = L[i];
}
if (head < tail)p[tail - 1] = linemeet(sta[tail], sta[tail - 1]);
}
while (head < tail && !onleft(sta[head], p[tail - 1]))tail--;
if (tail <= head + 1)return 0;
p[tail] = linemeet(sta[tail], sta[head]);
for (int i = head; i <= tail; ++i)Ans[i - head + 1] = p[i];
return tail - head + 1;
}
平衡树splay
int isr(int x) {return x == tr[tr[x].fa].ch[1];}
int js(int x) {return tr[tr[x].ch[0]].siz + 1;}
void updata(int x) {tr[x].siz = tr[tr[x].ch[0]].siz + tr[tr[x].ch[1]].siz + 1;}
void New(int x, int val)
{
tr[x].ch[0] = tr[x].ch[1] = tr[x].fa = 0;
tr[x].val = val; tr[x].siz = 1;
}
void rotate(int x)
{
int y = tr[x].fa, z = tr[y].fa, k = isr(x);
if (y != root)tr[z].ch[isr(y)] = x;
else root = x;
tr[y].ch[k] = tr[x].ch[!k]; tr[tr[y].ch[k]].fa = y;
tr[x].ch[!k] = y; tr[y].fa = x; tr[x].fa = z;
updata(y); updata(x);
}
void Splay(int x)
{
while (x != root)
{
if (tr[x].fa != root)rotate(isr(x) == isr(tr[x].fa) ? tr[x].fa : x);
rotate(x);
}
}
void Insert(int val)
{
if (!root)
{
root = (top ? zhan[top--] : ++cnt);
New(root, val);
return;
}
int now = root, fa = 0;
while (now) {fa = now; now = tr[now].ch[val > tr[now].val];}
now = (top ? zhan[top--] : ++cnt); New(now, val);
tr[fa].ch[tr[now].val > tr[fa].val] = now; tr[now].fa = fa;
Splay(now);
}
void Merge(int &x, int y, int fa)
{
if (x)tr[x].fa = fa;
if (y)tr[y].fa = fa;
if (!x || !y) {x = x + y; return;}
Merge(tr[x].ch[1], y, x);
updata(x);
}
void Delete(int val)
{
int now = root;
while (now && tr[now].val != val)now = tr[now].ch[val > tr[now].val];
if (!now)return;
zhan[++top] = now; Splay(now);
Merge(tr[now].ch[0], tr[now].ch[1], 0);
root = tr[now].ch[0];
}
int Rank(int val)
{
int now = root, fa = 0, res = 0;
while (now)
{
fa = now;
if (val <= tr[now].val)now = tr[now].ch[0];
else {res += js(now); now = tr[now].ch[1];}
}
Splay(fa);
return res + 1;
}
int Kth(int k)
{
int now = root;
while (now && js(now) != k)
{
if (k < js(now))now = tr[now].ch[0];
else {k -= js(now); now = tr[now].ch[1];}
}
Splay(now);
return tr[now].val;
}
int Pre(int val)
{
int now = root, last = 0;
while (now)
{
if (val > tr[now].val) {last = now; now = tr[now].ch[1];}
else now = tr[now].ch[0];
}
if (last) {Splay(last); return tr[last].val;}
return -1;
}
int Next(int val)
{
int now = root, last = 0;
while (now)
{
if (val < tr[now].val) {last = now; now = tr[now].ch[0];}
else now = tr[now].ch[1];
}
if (last) {Splay(last); return tr[last].val;}
return -1;
}
splay维护序列
void pushup(int x)
{
siz[x] = siz[lson] + siz[rson] + 1;
mx[x] = val[x];
if (lson)mx[x] = max(mx[x], mx[lson]);
if (rson)mx[x] = max(mx[x], mx[rson]);
}
void pushdown(int x)
{
if (rev[x])
{
swap(ch[lson][0], ch[lson][1]); swap(ch[rson][0], ch[rson][1]);
rev[lson] ^= 1; rev[rson] ^= 1; rev[x] = 0;
}
if (tag[x])
{
val[lson] += tag[x]; mx[lson] += tag[x]; val[rson] += tag[x]; mx[rson] += tag[x];
tag[lson] += tag[x]; tag[rson] += tag[x]; tag[x] = 0;
}
}
int isr(int x) {return ch[fa[x]][1] == x;}
void rotate(int x, int &to)
{
int y = fa[x], z = fa[y], k = isr(x);
if (y == to)to = x;
else ch[z][isr(y)] = x;
ch[y][k] = ch[x][!k]; fa[ch[y][k]] = y;
ch[x][!k] = y; fa[y] = x; fa[x] = z;
pushup(y); pushup(x);
}
void splay(int x, int &to)
{
while (x != to)
{
if (fa[x] != to)rotate(isr(x) == isr(fa[x]) ? fa[x] : x, to);
rotate(x, to);
}
}
int build(int l, int r)
{
if (l > r)return 0;
int mid = (l + r) >> 1, x = ++cnt; siz[x] = 1;
lson = build(l, mid - 1); fa[lson] = x;
rson = build(mid + 1, r); fa[rson] = x;
pushup(x);
return x;
}
int find(int x, int k)
{
while (1)
{
pushdown(x);
if (k <= siz[lson])x = lson;
else
{
k -= siz[lson] + 1;
if (!k)return x;
x = rson;
}
}
}
int split(int x, int y)
{
x = find(root, x); y = find(root, y);
splay(x, root); splay(y, ch[root][1]);
return ch[y][0];
}
LCT
inline int isr(int x) {return ch[fa[x]][1] == x;}
inline int isroot(int x) {return ch[fa[x]][0] != x && ch[fa[x]][1] != x;}
void pushup(int x) {sum[x] = val[x] ^ sum[lson] ^ sum[rson];}
void pushdown(int x)
{
if (rev[x])
{
swap(ch[lson][0], ch[lson][1]); swap(ch[rson][0], ch[rson][1]);
rev[lson] ^= 1; rev[rson] ^= 1; rev[x] = 0;
}
}
void upd(int x)
{
if (!isroot(x))upd(fa[x]); pushdown(x);
}
void rot(int x)
{
int y = fa[x], z = fa[y], k = isr(x);
if (!isroot(y))ch[z][isr(y)] = x;
ch[y][k] = ch[x][!k]; fa[ch[y][k]] = y;
ch[x][!k] = y; fa[y] = x; fa[x] = z;
pushup(y); pushup(x);
}
void Splay(int x)
{
upd(x);
while (!isroot(x))
{
if (!isroot(fa[x]))rot(isr(x) == isr(fa[x]) ? fa[x] : x);
rot(x);
}
}
void access(int x)
{
int t = 0;
while (x) {Splay(x); rson = t; pushup(x); t = x; x = fa[x];}
}
void make_root(int x)
{
access(x); Splay(x);
swap(lson, rson); rev[x] ^= 1;
}
void link(int x, int y) {make_root(x); fa[x] = y;}
void cut(int x, int y) {make_root(y); access(x); Splay(x); lson = fa[y] = 0;}
int find(int x)
{
access(x); Splay(x);
while (lson)pushdown(x), x = lson;
return x;
}
void change(int x, int v) {Splay(x); sum[x] ^= val[x]; val[x] = v; sum[x] ^= val[x];}
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; ++i)scanf("%d", &val[i]);
while (m--)
{
scanf("%d%d%d", &opt, &x, &y);
if (opt == 0)
{
make_root(x); access(y); Splay(y);
printf("%d\n", sum[y]);
} else if (opt == 1) {if (find(x) != find(y))link(x, y);}
else if (opt == 2) {if (find(x) == find(y) && (fa[x] == y || fa[y] == x))cut(x, y);}
else change(x, y);
}
return 0;
}