数据结构代码汇总

前言

本文均为本人码风qwq

另外有一些奇奇怪怪的东西……不知道算不算数据结构,就都放上了。 


线段树

线段树(区间加)(题目:洛谷P3372)

#include <bits/stdc++.h>
using namespace std;
#define MAXN 1000005
typedef long long ll;
ll n, m, a[MAXN], ans[MAXN << 2], tag[MAXN << 2], x, y, k, oper;
inline ll ls(ll p) {
    return p << 1;
}
inline ll rs(ll p) {
    return p << 1 | 1;
}
inline void push_up(ll p) { //do add
    ans[p] = ans[ls(p)] + ans[rs(p)];
}
void build(ll p, ll l, ll r) {
    tag[p] = 0;
    if (l == r) {
        ans[p] = a[l];
        return;
    }
    ll mid = l + r >> 1;
    build(ls(p), l, mid);
    build(rs(p), mid + 1, r);
    push_up(p);
}
inline void f(ll p, ll l, ll r, ll k) { //only modify ancestor
    tag[p] += k;
    ans[p] += k * (r - l + 1);
}
inline void push_down(ll p, ll l, ll r) {
    ll mid = (l + r) >> 1;
    f(ls(p), l, mid, tag[p]);
    f(rs(p), mid + 1, r, tag[p]);
    tag[p] = 0;
}
inline void update(ll dl, ll dr, ll l, ll r, ll p, ll k) {
    if (dl <= l && r <= dr) {
        ans[p] += k * (r - l + 1);
        tag[p] += k;
        return;
    }
    push_down(p, l, r);
    ll mid = l + r >> 1;
    if (dl <= mid)update(dl, dr, l, mid, ls(p), k);
    if (mid < dr)update(dl, dr, mid + 1, r, rs(p), k);
    push_up(p);
}
ll query(ll qx, ll qy, ll l, ll r, ll p) {
    ll res = 0;
    if (qx <= l && r <= qy)return ans[p];
    ll mid = l + r >> 1;
    push_down(p, l, r);
    if (qx <= mid)res += query(qx, qy, l, mid, ls(p));
    if (qy > mid)res += query(qx, qy, mid + 1, r, rs(p));
    return res;
}
int main() {
    scanf("%lld%lld", &n, &m);
    for (int i = 1; i <= n; i++)scanf("%lld", &a[i]);
    build(1, 1, n);
    while (m--) {
        scanf("%lld", &oper);
        if (oper == 1) {
            scanf("%lld%lld%lld", &x, &y, &k);
            update(x, y, 1, n, 1, k);
        }
        else {
            scanf("%lld%lld", &x, &y);
            printf("%lld\n", query(x, y, 1, n, 1));
        }
    }
    return 0;
}
View Code

 

线段树(区间加、区间乘)(洛谷P3373)

#include <bits/stdc++.h>
using namespace std;
#define MAXN 1000005
typedef long long ll;
ll n, m, a[MAXN], ans[MAXN << 2], add[MAXN << 2], mul[MAXN << 2], x, y, k, oper, mod;
inline ll ls(ll p) {
    return p << 1;
}
inline ll rs(ll p) {
    return p << 1 | 1;
}
inline void push_up(ll p) {
    ans[p] = (ans[ls(p)] + ans[rs(p)]) % mod;
}
void build(ll p, ll l, ll r) {
    add[p] = 0;
    mul[p] = 1;
    if (l == r) {
        ans[p] = a[l];
        return;
    }
    ll mid = l + r >> 1;
    build(ls(p), l, mid);
    build(rs(p), mid + 1, r);
    push_up(p);
}
inline void f(ll p, ll l, ll r,ll fa) {
    mul[p] = (mul[p] * mul[fa]) % mod;
    add[p] = (add[p] * mul[fa] + add[fa]) % mod;
    ans[p] = (ans[p] * mul[fa] + add[fa] * (r - l + 1)) % mod;
}
inline void push_down(ll p, ll l, ll r) {
    ll mid = (l + r) >> 1;
    f(ls(p), l, mid, p);
    f(rs(p), mid + 1, r, p);
    mul[p] = 1;
    add[p] = 0;
}
inline void update(ll dl, ll dr, ll l, ll r, ll p, ll k, bool op) {
    if (dr < l || r < dl)return;
    if (dl <= l && r <= dr) {
        if (op == 1) {
            ans[p] = (ans[p] + k * (r - l + 1)) % mod;
            add[p] = (add[p] + k) % mod;
        }
        else {
            ans[p] = (ans[p] * k) % mod;
            mul[p] = (mul[p] * k) % mod;
            add[p] = (add[p] * k) % mod;
        }
        return;
    }
    push_down(p, l, r);
    ll mid = l + r >> 1;
    if (dl <= mid)update(dl, dr, l, mid, ls(p), k, op);
    if (mid < dr)update(dl, dr, mid + 1, r, rs(p), k, op);
    push_up(p);
}
ll query(ll qx, ll qy, ll l, ll r, ll p) {
    if (qy < l || r < qx)return 0;
    if (qx <= l && r <= qy)return ans[p];
    ll res = 0;
    ll mid = l + r >> 1;
    push_down(p, l, r);
    if (qx <= mid)res += query(qx, qy, l, mid, ls(p));
    if (qy > mid)res += query(qx, qy, mid + 1, r, rs(p));
    return res % mod;
}
int main() {
    scanf("%lld%lld%lld", &n, &m, &mod);
    for (int i = 1; i <= n; i++)scanf("%lld", &a[i]);
    build(1, 1, n);
    while (m--) {
        scanf("%lld", &oper);
        switch (oper) {
        case 1:
            scanf("%lld%lld%lld", &x, &y, &k);
            update(x, y, 1, n, 1, k, 0);
            break;
        case 2:
            scanf("%lld%lld%lld", &x, &y, &k);
            update(x, y, 1, n, 1, k, 1);
            break;
        default:
            scanf("%lld%lld", &x, &y);
            printf("%lld\n", query(x, y, 1, n, 1));
        }
    }
    return 0;
}
View Code

 

线段树(区间最大连续子序列)(洛谷P4513)

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 5e5 + 5;
int n, m, t[MAXN << 2], sum[MAXN << 2], L[MAXN << 2], R[MAXN << 2];
struct node
{
    int t, sum, L, R;
};
inline int ls(int p)
{
    return p << 1;
}
inline int rs(int p)
{
    return p << 1 | 1;
}
inline void push_up(int p)
{
    sum[p] = sum[ls(p)] + sum[rs(p)];
    L[p] = max(L[ls(p)], sum[ls(p)] + L[rs(p)]);
    R[p] = max(R[rs(p)], sum[rs(p)] + R[ls(p)]);
    t[p] = max(max(t[ls(p)], t[rs(p)]), R[ls(p)] + L[rs(p)]);
}
void build(int p, int l, int r)
{
    if (l == r)
    {
        cin >> t[p];
        sum[p] = L[p] = R[p] = t[p];
        return;
    }
    int mid = l + r >> 1;
    build(ls(p), l, mid);
    build(rs(p), mid + 1, r);
    push_up(p);
}
void update(int p, int l, int r, int x, int k)
{
    if (l == r)
    {
        L[p] = R[p] = t[p] = sum[p] = k;
        return;
    }
    int mid = l + r >> 1;
    if (x <= mid)
        update(ls(p), l, mid, x, k);
    else
        update(rs(p), mid + 1, r, x, k);
    push_up(p);
}
node query(int p, int l, int r, int qx, int qy)
{
    if (qx <= l && r <= qy)
        return (node){t[p], sum[p], L[p], R[p]};
    int mid = l + r >> 1;
    if (qy <= mid) // all in left
        return query(ls(p), l, mid, qx, qy);
    else if (qx > mid) // all in right
        return query(rs(p), mid + 1, r, qx, qy);
    else
    {
        node ql = query(ls(p), l, mid, qx, qy), qr = query(rs(p), mid + 1, r, qx, qy);
        return (node){max(max(ql.t, qr.t), ql.R + qr.L), ql.sum + qr.sum, max(ql.L, ql.sum + qr.L), max(qr.R, qr.sum + ql.R)};
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> m;
    build(1, 1, n);
    int op, x, y;
    for (int i = 1; i <= m; i++)
    {
        cin >> op >> x >> y;
        if (op == 1)
            cout << query(1, 1, n, min(x, y), max(x, y)).t << '\n';
        else
            update(1, 1, n, x, y);
    }
    return 0;
}
View Code

 

线段树合并(洛谷P4556)

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
int n, m, mx, head[MAXN], to[MAXN << 1], nxt[MAXN << 1], d[MAXN], g[MAXN][25], tot, cnt;
int t[MAXN << 6], c[MAXN << 6], ch[MAXN << 6][2], root[MAXN], ans[MAXN];
struct node
{
    int u, v, w;
} q[MAXN];
inline void link(int u, int v)
{
    to[tot] = v;
    nxt[tot] = head[u];
    head[u] = tot++;
}
inline int ls(int p)
{
    return p << 1;
}
inline int rs(int p)
{
    return p << 1 | 1;
}
inline void init(int x, int fa)
{
    g[x][0] = fa;
    d[x] = d[fa] + 1;
    for (int i = 1; 1 << i <= d[x]; i++)
        g[x][i] = g[g[x][i - 1]][i - 1];
    for (int i = head[x]; ~i; i = nxt[i])
        if (to[i] != fa)
            init(to[i], x);
}
inline int LCA(int u, int v)
{
    if (d[u] < d[v])
        swap(u, v);
    for (int i = 20; i >= 0; i--)
        if (d[g[u][i]] >= d[v])
            u = g[u][i];
    if (u == v)
        return u;
    for (int i = 20; i >= 0; i--)
        if (g[u][i] != g[v][i])
        {
            u = g[u][i];
            v = g[v][i];
        }
    return g[u][0];
}
inline void push_up(int p)
{
    if (c[ch[p][0]] >= c[ch[p][1]])
    {
        c[p] = c[ch[p][0]];
        t[p] = t[ch[p][0]];
    }
    else
    {
        c[p] = c[ch[p][1]];
        t[p] = t[ch[p][1]];
    }
}
inline void Insert(int &p, int l, int r, int x, int k)
{
    if (!p)
        p = ++cnt;
    if (l == r)
    {
        c[p] += k;
        t[p] = l;
        return;
    }
    int mid = l + r >> 1;
    if (x <= mid)
        Insert(ch[p][0], l, mid, x, k);
    else
        Insert(ch[p][1], mid + 1, r, x, k);
    push_up(p);
}
inline int Merge(int l, int r, int x, int y)
{
    if (!x || !y)
        return x + y;
    if (l == r)
    {
        c[x] += c[y];
        t[x] = l;
        return x;
    }
    int mid = l + r >> 1;
    ch[x][0] = Merge(l, mid, ch[x][0], ch[y][0]);
    ch[x][1] = Merge(mid + 1, r, ch[x][1], ch[y][1]);
    push_up(x);
    return x;
}
inline void dfs(int x)
{
    for (int i = head[x]; ~i; i = nxt[i])
        if (d[to[i]] > d[x])
        {
            dfs(to[i]);
            root[x] = Merge(1, mx, root[x], root[to[i]]);
        }
    if (c[root[x]])
        ans[x] = t[root[x]];
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    memset(head, -1, sizeof(head));
    cin >> n >> m;
    int u, v;
    for (int i = 1; i < n; i++)
    {
        cin >> u >> v;
        link(u, v);
        link(v, u);
    }
    init(1, 0);
    for (int i = 1; i <= m; i++)
    {
        cin >> q[i].u >> q[i].v >> q[i].w;
        mx = max(mx, q[i].w);
    }
    for (int i = 1; i <= m; i++)
    {
        int lca = LCA(q[i].u, q[i].v);
        Insert(root[q[i].u], 1, mx, q[i].w, 1);
        Insert(root[q[i].v], 1, mx, q[i].w, 1);
        Insert(root[lca], 1, mx, q[i].w, -1);
        if (g[lca][0])
            Insert(root[g[lca][0]], 1, mx, q[i].w, -1);
    }
    dfs(1);
    for (int i = 1; i <= n; i++)
        cout << ans[i] << '\n';
    return 0;
}
View Code

 

线段树维护单调栈(洛谷P4198)

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
int n, m, g[MAXN << 2];
double f[MAXN << 2], slp[MAXN];
inline int ls(int p)
{
    return p << 1;
}
inline int rs(int p)
{
    return p << 1 | 1;
}
inline void push_up(int p)
{
    f[p] = max(f[ls(p)], f[rs(p)]);
}
inline int query(int p, int l, int r, double x)
{
    if (f[p] <= x)
        return 0;
    if (x < slp[l])
        return g[p];
    if (l == r)
        return x < slp[l];
    int mid = l + r >> 1;
    if (f[ls(p)] <= x)
        return query(rs(p), mid + 1, r, x);
    else
        return query(ls(p), l, mid, x) + g[p] - g[ls(p)];
}
inline void update(int p, int l, int r, int x, int k)
{
    if (l == x && r == x)
    {
        f[p] = 1.0 * k / x;
        g[p] = 1;
        return;
    }
    int mid = l + r >> 1;
    if (x <= mid)
        update(ls(p), l, mid, x, k);
    else
        update(rs(p), mid + 1, r, x, k);
    push_up(p);
    g[p] = g[ls(p)] + query(rs(p), mid + 1, r, f[ls(p)]);
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> m;
    int x, y;
    for (int i = 1; i <= m; i++)
    {
        cin >> x >> y;
        slp[x] = 1.0 * y / x;
        update(1, 1, n, x, y);
        cout << g[1] << '\n';
    }
    return 0;
}
View Code

 

李超线段树(P4097)

#include <bits/stdc++.h>
using namespace std;
const int mod1 = 39989;
const int mod2 = 1e9;
const int N = 1e5 + 5;
const int M = 4e4 + 5;
const double eps = 1e-9;
int n, t[M << 3], tot;
struct line
{
    double k, b;
} a[N];
inline int ls(int p)
{
    return p << 1;
}
inline int rs(int p)
{
    return p << 1 | 1;
}
inline int cmp(double x, double y)
{
    if (x - y > eps)
        return 1;
    if (y - x > eps)
        return -1;
    return 0;
}
struct result
{
    double x;
    int y;
    inline result()
    {
    }
    inline result(double _x, int _y)
    {
        x = _x, y = _y;
    }
    inline const bool operator<(const result &t) const
    {
        if (cmp(x, t.x) == -1)
            return true;
        if (cmp(x, t.x) == 1)
            return false;
        return y > t.y;
    }
};
inline double calc(int x, int d)
{
    return a[x].b + a[x].k * d;
}
inline void add(int x0, int y0, int x1, int y1)
{
    if (x0 == x1) // slope = inf
        a[++tot] = (line){0, 1.0 * max(y0, y1)};
    else
    {
        double slope = 1.0 * (y1 - y0) / (x1 - x0);
        a[++tot] = (line){slope, y0 - slope * x0};
    }
}
inline void upd(int p, int l, int r, int k)
{
    int &x = t[p], mid = l + r >> 1;
    if (cmp(calc(k, mid), calc(x, mid)) == 1)
        swap(k, x);
    int bl = cmp(calc(k, l), calc(x, l)), br = cmp(calc(k, r), calc(x, r));
    if (bl == 1 || (!bl && k < x))
        upd(ls(p), l, mid, k);
    if (br == 1 || (!br && k < x))
        upd(rs(p), mid + 1, r, k);
}
inline void update(int p, int l, int r, int dl, int dr, int k)
{
    if (dl <= l && r <= dr)
    {
        upd(p, l, r, k);
        return;
    }
    int mid = l + r >> 1;
    if (dl <= mid)
        update(ls(p), l, mid, dl, dr, k);
    if (mid < dr)
        update(rs(p), mid + 1, r, dl, dr, k);
}
result query(int p, int l, int r, int k)
{
    // cout << p << ' ' << t[p] << ' ' << l << ' ' << r << ' ' << k << '\n';
    if (r < k || k < l)
        return result(0, 0);
    int mid = l + r >> 1;
    double res = calc(t[p], k);
    if (l == r)
        return result(res, t[p]);
    return max({result(res, t[p]), query(ls(p), l, mid, k), query(rs(p), mid + 1, r, k)});
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int last = 0;
    cin >> n;
    while (n--)
    {
        int op;
        cin >> op;
        if (!op)
        {
            int x;
            cin >> x;
            x = (x + last - 1 + mod1) % mod1 + 1;
            last = query(1, 1, mod1, x).y;
            cout << last << '\n';
        }
        else
        {
            int x0, y0, x1, y1;
            cin >> x0 >> y0 >> x1 >> y1;
            x0 = (x0 + last - 1 + mod1) % mod1 + 1;
            x1 = (x1 + last - 1 + mod1) % mod1 + 1;
            y0 = (y0 + last - 1 + mod2) % mod2 + 1;
            y1 = (y1 + last - 1 + mod2) % mod2 + 1;
            if (x0 > x1)
                swap(x0, x1), swap(y0, y1);
            add(x0, y0, x1, y1);
            update(1, 1, mod1, x0, x1, tot);
        }
    }
    return 0;
}
View Code

  


ST表

ST表维护区间最大值(洛谷P3865)

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n, m, st[N][25];
inline int query(int l, int r)
{
    int k = log2(r - l + 1);
    return max(st[l][k], st[r - (1 << k) + 1][k]);
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        cin >> st[i][0];
    for (int i = 1; i <= 20; i++)
        for (int j = 1; j + (1 << i) - 1 <= n; j++)
            st[j][i] = max(st[j][i - 1], st[j + (1 << i - 1)][i - 1]);
    while (m--)
    {
        int l, r;
        cin >> l >> r;
        cout << query(l, r) << '\n';
    }
    return 0;
}
View Code

 

 


树状数组

树状数组(单点加,区间查询)(洛谷3374)

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 5e5 + 5;
int n, m, t[MAXN << 2];
inline int lowbit(int x)
{
    return x & -x;
}
void add(int x, int k)
{
    while (x <= n)
    {
        t[x] += k;
        x += lowbit(x);
    }
}
int query(int x)
{
    int res = 0;
    while (x)
    {
        res += t[x];
        x -= lowbit(x);
    }
    return res;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> m;
    int tmp, op, x, y;
    for (int i = 1; i <= n; i++)
    {
        cin >> tmp;
        add(i, tmp);
    }
    while (m--)
    {
        cin >> op >> x >> y;
        if (op == 1)
            add(x, y);
        else
            cout << query(y) - query(x - 1) << '\n';
    }
    return 0;
}
View Code

 

树状数组(区间加、单点查询)(洛谷P3368)

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 5e5 + 5;
int n, m, t[MAXN << 2];
inline int lowbit(int x)
{
    return x & -x;
}
void add(int x, int k)
{
    while (x <= n)
    {
        t[x] += k;
        x += lowbit(x);
    }
}
int query(int x)
{
    int res = 0;
    while (x)
    {
        res += t[x];
        x -= lowbit(x);
    }
    return res;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> m;
    int tmp, op, x, y, k, last = 0;
    for (int i = 1; i <= n; i++)
    {
        cin >> tmp;
        add(i, tmp - last);
        last = tmp;
    }
    while (m--)
    {
        cin >> op;
        if (op == 1)
        {
            cin >> x >> y >> k;
            add(x, k);
            add(y + 1, -k);
        }
        else
        {
            cin >> x;
            cout << query(x) << '\n';
        }
    }
    return 0;
}
View Code

 


平衡树

平衡树(Treap)(洛谷P3369)

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 3e6 + 5;
const int INF = 0x3f3f3f3f;
int n, oper, x;
int ch[MAXN][2], val[MAXN], pri[MAXN], sz[MAXN], cnt[MAXN], sum, root; // ch[x][0]=left, ch[x][1]=right
inline int add(int x)
{
    sum++;                           // how many node
    val[sum] = x;                    // node value
    pri[sum] = rand(); // node priority
    sz[sum] = 1;                     // node size
    cnt[sum] = 1;                    // number of same value
    return sum;
}
inline void push_up(int x)
{
    sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + cnt[x];
}
void build()
{
    root = add(-INF);
    ch[root][1] = add(INF);
    push_up(root);
}
void Rotate(int &x, int d)
{
    int tmp = ch[x][d ^ 1];
    ch[x][d ^ 1] = ch[tmp][d];
    ch[tmp][d] = x;
    x = tmp;
    push_up(ch[x][d]);
    push_up(x);
}
void Insert(int &x, int v)
{
    if (!x)
    {
        x = add(v);
        return;
    }
    if (v == val[x])
        cnt[x]++;
    else
    {
        int b = v < val[x] ? 0 : 1;
        Insert(ch[x][b], v);
        if (pri[x] < pri[ch[x][b]])
            Rotate(x, b ^ 1);
    }
    push_up(x);
}
void Remove(int &x, int v)
{
    if (!x) // not find
        return;
    if (val[x] == v) // find
    {
        if (cnt[x] > 1) // more than 1
        {
            cnt[x]--;
            push_up(x);
        }
        else if (ch[x][0] || ch[x][1]) // only 1, and has child
        {
            if (!ch[x][1] || pri[ch[x][0]] > pri[ch[x][1]])
            {
                Rotate(x, 1);
                Remove(ch[x][1], v);
            }
            else
            {
                Rotate(x, 0);
                Remove(ch[x][0], v);
            }
            push_up(x);
        }
        else
            x = 0;
        return;
    }
    if (v < val[x]) // at left
        Remove(ch[x][0], v);
    else // at right
        Remove(ch[x][1], v);
    push_up(x);
}
int Rank(int x, int v)
{
    if (!x) // not find
        return 0;
    if (v == val[x]) // find
        return sz[ch[x][0]] + 1;
    else if (v < val[x]) // at left
        return Rank(ch[x][0], v);
    else // at right
        return sz[ch[x][0]] + cnt[x] + Rank(ch[x][1], v);
}
int Value(int x, int v)
{
    if (!x) // not find
        return INF;
    if (v <= sz[ch[x][0]]) // at left
        return Value(ch[x][0], v);
    else if (v <= sz[ch[x][0]] + cnt[x]) // find
        return val[x];
    else // at right
        return Value(ch[x][1], v - (sz[ch[x][0]] + cnt[x]));
}
int Previous(int v)
{
    int x = root, res;
    while (x)
        if (v > val[x])
        {
            res = val[x];
            x = ch[x][1]; // left
        }
        else
            x = ch[x][0]; // right
    return res;
}
int Next(int v)
{
    int x = root, res;
    while (x)
        if (v < val[x])
        {
            res = val[x];
            x = ch[x][0]; // right
        }
        else
            x = ch[x][1]; // left
    return res;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> n;
    build();
    while (n--)
    {
        cin >> oper >> x;
        switch (oper)
        {
        case 1:
            Insert(root, x);
            break;
        case 2:
            Remove(root, x);
            break;
        case 3:
            cout << Rank(root, x) - 1 << '\n';
            break;
        case 4:
            cout << Value(root, x + 1) << '\n';
            break;
        case 5:
            cout << Previous(x) << '\n';
            break;
        default:
            cout << Next(x) << '\n';
        }
    }
    return 0;
}
View Code

 

平衡树(FHQ-Treap)(推荐)(洛谷P3369)

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 3e6 + 5;
int root, val[MAXN], sz[MAXN], ch[MAXN][2], pri[MAXN], tot;
int n, opt, x;
inline int add(int x)
{
    val[++tot] = x;
    sz[tot] = 1;
    pri[tot] = rand();
    return tot;
}
inline void push_up(int x)
{
    sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + 1;
}
int Merge(int x, int y)
{
    if (!x || !y)
        return x + y;
    if (pri[x] < pri[y])
    {
        ch[x][1] = Merge(ch[x][1], y);
        push_up(x);
        return x;
    }
    else
    {
        ch[y][0] = Merge(x, ch[y][0]);
        push_up(y);
        return y;
    }
}
void Split(int cur, int k, int &x, int &y)
{
    if (!cur)
    {
        x = y = 0;
        return;
    }
    if (val[cur] <= k) // left
    {
        x = cur;
        Split(ch[cur][1], k, ch[cur][1], y);
    }
    else // right
    {
        y = cur;
        Split(ch[cur][0], k, x, ch[cur][0]);
    }
    push_up(cur);
}
int Find(int cur, int k)
{
    while (true)
        if (sz[ch[cur][0]] >= k)
            cur = ch[cur][0];
        else if (sz[ch[cur][0]] + 1 == k)
            return cur;
        else
        {
            k -= sz[ch[cur][0]] + 1;
            cur = ch[cur][1];
        }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n;
    int x, y, z, tmp;
    while (n--)
    {
        cin >> opt >> tmp;
        switch (opt)
        {
        case 1: // Add
            Split(root, tmp, x, y);
            root = Merge(Merge(x, add(tmp)), y);
            break;
        case 2: // Delete
            Split(root, tmp, x, z);
            Split(x, tmp - 1, x, y);
            y = Merge(ch[y][0], ch[y][1]);
            root = Merge(Merge(x, y), z);
            break;
        case 3: // Rank
            Split(root, tmp - 1, x, y);
            cout << sz[x] + 1 << '\n'; // left tree
            root = Merge(x, y);
            break;
        case 4: // Find Num
            cout << val[Find(root, tmp)] << '\n';
            break;
        case 5: // Find Last
            Split(root, tmp - 1, x, y);
            cout << val[Find(x, sz[x])] << '\n';
            root = Merge(x, y);
            break;
        default: // Find Next
            Split(root, tmp, x, y);
            cout << val[Find(y, 1)] << '\n';
            root = Merge(x, y);
        }
    }
    return 0;
}
View Code

 

文艺平衡树(FHQ-Treap)(洛谷P3391)

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 5e6;
int root, val[MAXN], ch[MAXN][2], pri[MAXN], sz[MAXN], tot;
bool f[MAXN];
inline int Add(int x)
{
    val[++tot] = x;
    sz[tot] = 1;
    pri[tot] = rand();
    return tot;
}
inline void push_up(int x)
{
    sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + 1;
}
inline void push_down(int x)
{
    swap(ch[x][0], ch[x][1]);
    if (ch[x][0])
        f[ch[x][0]] ^= 1;
    if (ch[x][1])
        f[ch[x][1]] ^= 1;
    f[x] = false;
}
int Merge(int x, int y)
{
    if (!x || !y)
        return x + y;
    if (pri[x] < pri[y])
    {
        if (f[x])
            push_down(x);
        ch[x][1] = Merge(ch[x][1], y);
        push_up(x);
        return x;
    }
    else
    {
        if (f[y])
            push_down(y);
        ch[y][0] = Merge(x, ch[y][0]);
        push_up(y);
        return y;
    }
}
void Split(int cur, int k, int &x, int &y)
{
    if (!cur)
    {
        x = y = 0;
        return;
    }
    if (f[cur])
        push_down(cur);
    if (sz[ch[cur][0]] < k)
    {
        x = cur;
        Split(ch[cur][1], k - sz[ch[cur][0]] - 1, ch[cur][1], y);
    }
    else
    {
        y = cur;
        Split(ch[cur][0], k, x, ch[cur][0]);
    }
    push_up(cur);
}
void print(int x)
{
    if (!x)
        return;
    if (f[x])
        push_down(x);
    print(ch[x][0]);
    cout << val[x] << ' ';
    print(ch[x][1]);
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n, m, l, r, x, y, z;
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        root = Merge(root, Add(i));
    while (m--)
    {
        cin >> l >> r;
        Split(root, l - 1, x, y);
        Split(y, r - l + 1, y, z);
        f[y] ^= 1;
        root = Merge(x, Merge(y, z));
    }
    print(root);
    return 0;
}
View Code

 


可持久化

主席树维护数组(洛谷P3919)

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e6 + 5;
int n, m, t[MAXN * 25], ch[MAXN * 25][2], tot, a[MAXN], root[MAXN];
void build(int l, int r, int &p)
{
    p = ++tot;
    if (l == r)
    {
        t[p] = a[l];
        return;
    }
    int mid = l + r >> 1;
    build(l, mid, ch[p][0]);
    build(mid + 1, r, ch[p][1]);
}
void update(int l, int r, int &p, int pre, int x, int k)
{
    p = ++tot;
    ch[p][0] = ch[pre][0];
    ch[p][1] = ch[pre][1];
    if (l == r)
    {
        t[p] = k;
        return;
    }
    int mid = l + r >> 1;
    if (x <= mid)
        update(l, mid, ch[p][0], ch[pre][0], x, k);
    else
        update(mid + 1, r, ch[p][1], ch[pre][1], x, k);
}
int query(int l, int r, int p, int x)
{
    if (l == r)
        return t[p];
    int mid = l + r >> 1;
    return x <= mid ? query(l, mid, ch[p][0], x) : query(mid + 1, r, ch[p][1], x);
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    build(1, n, root[0]);
    int x, y, z, v;
    for (int i = 1; i <= m; i++)
    {
        cin >> x >> y >> z;
        if (y == 1)
        {
            cin >> v;
            update(1, n, root[i], root[x], z, v);
        }
        else
        {
            cout << query(1, n, root[x], z) << '\n';
            root[i] = root[x];
        }
    }
    return 0;
}
View Code

 

主席树-权值线段树(洛谷P3834)

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
int n, m, cnt, root[MAXN];
struct node
{
    int ls, rs, sz;
} t[MAXN << 5];
inline int update(int pre, int l, int r, int k)
{
    int root = ++cnt;
    t[root] = t[pre];
    t[root].sz++;
    if (l == r)
        return root;
    int mid = l + r >> 1;
    if (k <= mid)
        t[root].ls = update(t[pre].ls, l, mid, k);
    else
        t[root].rs = update(t[pre].rs, mid + 1, r, k);
    return root;
}
inline int query(int p1, int p2, int l, int r, int k)
{
    if (l == r)
        return l;
    int mid = l + r >> 1;
    if (k <= t[t[p2].ls].sz - t[t[p1].ls].sz)
        return query(t[p1].ls, t[p2].ls, l, mid, k);
    else
        return query(t[p1].rs, t[p2].rs, mid + 1, r, k + t[t[p1].ls].sz - t[t[p2].ls].sz);
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> m;
    for (int i = 1, x; i <= n; i++)
    {
        cin >> x;
        root[i] = update(root[i - 1], -1e9, 1e9, x);
    }
    for (int i = 1, l, r, k; i <= m; i++)
    {
        cin >> l >> r >> k;
        cout << query(root[l - 1], root[r], -1e9, 1e9, k) << '\n';
    }
    return 0;
}
View Code

 

可持久化平衡树(FHQ-Treap)(洛谷P3835)

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 2.5e7 + 5;
int ch[MAXN][2], val[MAXN], sz[MAXN], pri[MAXN], tot, root[MAXN], n;
inline int add(int x)
{
    val[++tot] = x;
    sz[tot] = 1;
    pri[tot] = rand();
    return tot;
}
inline void push_up(int x)
{
    sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + 1;
}
int Merge(int x, int y)
{
    if (!x || !y)
        return x + y;
    if (pri[x] < pri[y])
    {
        int tmp = add(0);
        val[tmp] = val[x];
        pri[tmp] = pri[x];
        sz[tmp] = sz[x];
        ch[tmp][0] = ch[x][0];
        ch[tmp][1] = ch[x][1];
        ch[tmp][1] = Merge(ch[tmp][1], y);
        push_up(tmp);
        return tmp;
    }
    else
    {
        int tmp = add(0);
        val[tmp] = val[y];
        pri[tmp] = pri[y];
        sz[tmp] = sz[y];
        ch[tmp][1] = ch[y][1];
        ch[tmp][0] = ch[y][0];
        ch[tmp][0] = Merge(x, ch[tmp][0]);
        push_up(tmp);
        return tmp;
    }
}
void Split(int cur, int k, int &x, int &y)
{
    if (!cur)
    {
        x = y = 0;
        return;
    }
    if (val[cur] <= k)
    {
        x = add(0);
        val[x] = val[cur];
        pri[x] = pri[cur];
        sz[x] = sz[cur];
        ch[x][0] = ch[cur][0];
        ch[x][1] = ch[cur][1];
        Split(ch[x][1], k, ch[x][1], y);
        push_up(x);
    }
    else
    {
        y = add(0);
        val[y] = val[cur];
        pri[y] = pri[cur];
        sz[y] = sz[cur];
        ch[y][0] = ch[cur][0];
        ch[y][1] = ch[cur][1];
        Split(ch[y][0], k, x, ch[y][0]);
        push_up(y);
    }
}
int Find(int cur, int k)
{
    while (true)
        if (sz[ch[cur][0]] >= k)
            cur = ch[cur][0];
        else
        {
            k -= sz[ch[cur][0]];
            if (!--k)
                return cur;
            cur = ch[cur][1];
        }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> n;
    int x, y, z, v, opt, a;
    for (int i = 1; i <= n; i++)
    {
        cin >> v >> opt >> a;
        root[i] = root[v];
        switch (opt)
        {
        case 1:
            Split(root[i], a, x, y);
            root[i] = Merge(Merge(x, add(a)), y);
            break;
        case 2:
            Split(root[i], a, x, z);
            Split(x, a - 1, x, y);
            y = Merge(ch[y][0], ch[y][1]);
            root[i] = Merge(Merge(x, y), z);
            break;
        case 3:
            Split(root[i], a - 1, x, y);
            cout << sz[x] + 1 << '\n';
            root[i] = Merge(x, y);
            break;
        case 4:
            cout << val[Find(root[i], a)] << '\n';
            break;
        case 5:
            Split(root[i], a - 1, x, y);
            if (!x)
                printf("-2147483647\n");
            else
            {
                cout << val[Find(x, sz[x])] << '\n';
                root[i] = Merge(x, y);
            }
            break;
        default:
            Split(root[i], a, x, y);
            if (!y)
            {
                printf("2147483647\n");
                continue;
            }
            cout << val[Find(y, 1)] << '\n';
            root[i] = Merge(x, y);
        }
    }
    return 0;
}
View Code

 

可持久化Trie

int t[N * 30][2], val[N * 30], root[N], tot;
inline void insert(int x, int last, int k)
{
    for (int i = 27; i >= 0; i--)
    {
        val[x] = val[last] + 1;
        bool p = k >> i & 1;
        if (!t[x][p])
            t[x][p] = ++tot;
        t[x][p ^ 1] = t[last][p ^ 1];
        x = t[x][p];
        last = t[last][p];
    }
    val[x] = val[last] + 1;
}
inline int query(int x, int y, int k)
{
    int res = 0;
    for (int i = 27; i >= 0; i--)
    {
        bool p = k >> i & 1;
        if (val[t[x][p ^ 1]] != val[t[y][p ^ 1]])
        {
            res += 1 << i;
            x = t[x][p ^ 1], y = t[y][p ^ 1];
        }
        else
            x = t[x][p], y = t[y][p];
    }
    return res;
}
View Code

 


树套树

线段树套FHQ-Treap(洛谷P3380)

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 5e4 + 5;
const int MAXM = 1e7 + 5;
const int INF = 2147483647;
int n, m, a[MAXN];
inline int read()
{
    int s = 0, f = 1;
    char ch = getchar();
    while (ch < 48 || ch > 57)
    {
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (ch >= 48 && ch <= 57)
    {
        s = (s << 3) + (s << 1) + (ch ^ 48);
        ch = getchar();
    }
    return s * f;
}
namespace FHQ
{
    int ch[MAXM][2], pri[MAXM], sz[MAXM], val[MAXM], tot = 0;
    // --- bottom ---
    inline int Add(int x)
    {
        val[++tot] = x;
        pri[tot] = rand();
        sz[tot] = 1;
        return tot;
    }
    inline void push_up(int x)
    {
        sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + 1;
    }
    inline int Merge(int x, int y)
    {
        if (!x || !y)
            return x + y;
        if (pri[x] < pri[y])
        {
            ch[x][1] = Merge(ch[x][1], y);
            push_up(x);
            return x;
        }
        else
        {
            ch[y][0] = Merge(x, ch[y][0]);
            push_up(y);
            return y;
        }
    }
    inline void Split(int cur, int k, int &x, int &y)
    {
        if (!cur)
        {
            x = y = 0;
            return;
        }
        if (val[cur] <= k)
        {
            x = cur;
            Split(ch[cur][1], k, ch[cur][1], y);
        }
        else
        {
            y = cur;
            Split(ch[cur][0], k, x, ch[cur][0]);
        }
        push_up(cur);
    }
    inline int Find(int cur, int k)
    {
        while (true)
            if (sz[ch[cur][0]] >= k)
                cur = ch[cur][0];
            else if (sz[ch[cur][0]] + 1 == k)
                return cur;
            else
            {
                k -= sz[ch[cur][0]] + 1;
                cur = ch[cur][1];
            }
    }
    // --- application ---
    inline void Insert(int &root, int k)
    {
        int x, y;
        Split(root, k, x, y);
        root = Merge(x, Merge(Add(k), y));
    }
    inline void Delete(int &root, int k)
    {
        int x, y, z;
        Split(root, k, x, z);
        Split(x, k - 1, x, y);
        y = Merge(ch[y][0], ch[y][1]);
        root = Merge(x, Merge(y, z));
    }
    inline int Rank(int root, int k)
    {
        int x, y;
        Split(root, k - 1, x, y);
        int ans = sz[x] + 1;
        root = Merge(x, y);
        return ans;
    }
    inline int Last(int root, int k)
    {
        int x, y;
        Split(root, k - 1, x, y);
        int ans = sz[x] ? val[Find(x, sz[x])] : -INF;
        root = Merge(x, y);
        return ans;
    }
    inline int Next(int root, int k)
    {
        int x, y;
        Split(root, k, x, y);
        int ans = sz[y] ? val[Find(y, 1)] : INF;
        root = Merge(x, y);
        return ans;
    }
    // --- level 2 application ---
    inline void build(int &root, int l, int r)
    {
        for (int i = l; i <= r; i++)
            Insert(root, a[i]);
    }
}
namespace SegTree
{
    int t[MAXN << 2], root[MAXN << 2];
    inline int ls(int p)
    {
        return p << 1;
    }
    inline int rs(int p)
    {
        return p << 1 | 1;
    }
    inline void build(int p, int l, int r)
    {
        FHQ::build(root[p], l, r);
        if (l == r)
            return;
        int mid = l + r >> 1;
        build(ls(p), l, mid);
        build(rs(p), mid + 1, r);
    }
    inline void update(int p, int l, int r, int pre, int k)
    {
        FHQ::Delete(root[p], a[pre]);
        FHQ::Insert(root[p], k);
        if (l == r)
            return;
        int mid = l + r >> 1;
        if (pre <= mid)
            update(ls(p), l, mid, pre, k);
        else
            update(rs(p), mid + 1, r, pre, k);
    }
    inline int Rank(int p, int qx, int qy, int l, int r, int k)
    {
        if (qx > r || qy < l)
            return 0;
        if (qx <= l && r <= qy)
            return FHQ::Rank(root[p], k) - 1;
        int mid = l + r >> 1;
        return Rank(ls(p), qx, qy, l, mid, k) + Rank(rs(p), qx, qy, mid + 1, r, k);
    }
    inline int Find(int l, int r, int k)
    {
        int x = 0, y = 1e8;
        while (x <= y)
        {
            int mid = x + y >> 1;
            if (Rank(1, l, r, 1, n, mid) + 1 <= k)
                x = mid + 1;
            else
                y = mid - 1;
        }
        return x - 1;
    }
    inline int Last(int p, int qx, int qy, int l, int r, int k)
    {
        if (qx > r || qy < l)
            return -INF;
        if (qx <= l && r <= qy)
            return FHQ::Last(root[p], k);
        int mid = l + r >> 1;
        return max(Last(ls(p), qx, qy, l, mid, k), Last(rs(p), qx, qy, mid + 1, r, k));
    }
    inline int Next(int p, int qx, int qy, int l, int r, int k)
    {
        if (qx > r || qy < l)
            return INF;
        if (qx <= l && r <= qy)
            return FHQ::Next(root[p], k);
        int mid = l + r >> 1;
        return min(Next(ls(p), qx, qy, l, mid, k), Next(rs(p), qx, qy, mid + 1, r, k));
    }
}
int main()
{
    // ios::sync_with_stdio(false);
    // cin.tie(nullptr);
    // freopen("t.in", "r", stdin);
    n = read();
    m = read();
    for (int i = 1; i <= n; i++)
        a[i] = read();
    SegTree::build(1, 1, n);
    int op, x, y, z;
    while (m--)
    {
        op = read();
        x = read();
        y = read();
        if (op == 3)
        {
            SegTree::update(1, 1, n, x, y);
            a[x] = y;
            continue;
        }
        z = read();
        switch (op)
        {
        case 1:
            printf("%d\n", SegTree::Rank(1, x, y, 1, n, z) + 1);
            break;
        case 2:
            printf("%d\n", SegTree::Find(x, y, z));
            break;
        case 4:
            printf("%d\n", SegTree::Last(1, x, y, 1, n, z));
            break;
        default:
            printf("%d\n", SegTree::Next(1, x, y, 1, n, z));
        }
    }
    return 0;
}
View Code

 


LCT

LCT(洛谷P3690)

#include <bits/stdc++.h>
using namespace std;
const int N = 3e5 + 5;
int n, m, fa[N], ch[N][2], val[N], sum[N];
bool r[N];
inline bool isroot(int x)
{

    return ch[fa[x]][0] == x || ch[fa[x]][1] == x;
}
inline void push_up(int x)
{
    sum[x] = sum[ch[x][0]] ^ sum[ch[x][1]] ^ val[x];
}
inline void f(int x)
{
    swap(ch[x][0], ch[x][1]);
    r[x] ^= 1;
}
inline void push_down(int x)
{
    if (!r[x])
        return;
    if (ch[x][0])
        f(ch[x][0]);
    if (ch[x][1])
        f(ch[x][1]);
    r[x] = 0;
}
inline void Rotate(int x)
{
    int y = fa[x], z = fa[y], k = ch[y][1] == x, w = ch[x][k ^ 1];
    if (isroot(y))
        ch[z][ch[z][1] == y] = x;
    ch[x][k ^ 1] = y;
    ch[y][k] = w;
    if (w)
        fa[w] = y;
    fa[y] = x;
    fa[x] = z;
    push_up(y);
}
stack<int> stk;
inline void splay(int x)
{
    int cur = x;
    stk.emplace(cur);
    while (isroot(cur))
        stk.emplace(cur = fa[cur]);
    for (; !stk.empty(); stk.pop())
        push_down(stk.top());
    while (isroot(x))
    {
        int fat = fa[x], fafa = fa[fat];
        if (isroot(fat))
            Rotate((ch[fat][0] == x) ^ (ch[fafa][0] == fat) ? x : fat);
        Rotate(x);
    }
    push_up(x);
}
inline void access(int x)
{
    for (int y = 0; x; y = x, x = fa[x])
    {
        splay(x);
        ch[x][1] = y;
        push_up(x);
    }
}
inline void makeRoot(int x)
{
    access(x);
    splay(x);
    f(x);
}
inline int getRoot(int x)
{
    access(x);
    splay(x);
    while (ch[x][0])
        push_down(x), x = ch[x][0];
    splay(x);
    return x;
}
inline void Split(int x, int y)
{
    makeRoot(x);
    access(y);
    splay(y);
}
inline void link(int x, int y)
{
    makeRoot(x);
    if (getRoot(y) != x)
        fa[x] = y;
}
inline void cut(int x, int y)
{
    makeRoot(x);
    if (getRoot(y) == x && fa[y] == x && !ch[y][0])
    {
        fa[y] = ch[x][1] = 0;
        push_up(x);
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        cin >> val[i];
    while (m--)
    {
        int op, x, y;
        cin >> op >> x >> y;
        switch (op)
        {
        case 0:
            Split(x, y);
            cout << sum[y] << '\n';
            break;
        case 1:
            link(x, y);
            break;
        case 2:
            cut(x, y);
            break;
        default:
            splay(x);
            val[x] = y;
        }
    }
    return 0;
}
View Code

 


K-D Tree

K-D Tree(洛谷P4148/P4357)

typedef long long ll;
const int N = 2e5 + 5;
int n, m, tot, cnt;
ll ls[N], rs[N], minx[N], maxx[N], miny[N], maxy[N], sum[N], sz[N], dim[N], id[N];
priority_queue<ll, vector<ll>, greater<ll>> q;
struct node
{
    ll x, y, val;
} s[N];
inline bool cmpx(const int &x, const int &y)
{
    return s[x].x < s[y].x;
}
inline bool cmpy(const int &x, const int &y)
{
    return s[x].y < s[y].y;
}
inline ll sq(ll x)
{
    return x * x;
}
inline ll dis(int x, int y)
{
    return max(sq(s[x].x - minx[y]), sq(s[x].x - maxx[y])) + max(sq(s[x].y - miny[y]), sq(s[x].y - maxy[y]));
}
inline void upd(int x, int y)
{
    minx[x] = min(minx[x], minx[y]), maxx[x] = max(maxx[x], maxx[y]);
    miny[x] = min(miny[x], miny[y]), maxy[x] = max(maxy[x], maxy[y]);
}
inline void push_up(int x)
{
    minx[x] = maxx[x] = s[x].x, miny[x] = maxy[x] = s[x].y;
    if (ls[x])
        upd(x, ls[x]);
    if (rs[x])
        upd(x, rs[x]);
    sum[x] = sum[ls[x]] + sum[rs[x]] + s[x].val;
    sz[x] = sz[ls[x]] + sz[rs[x]] + 1;
}
inline int build(int l, int r)
{
    if (l > r)
        return 0;
    int mid = l + r >> 1;
    double sdx = 0, sdy = 0, dx = 0, dy = 0;
    for (int i = l; i <= r; i++)
        sdx += s[id[i]].x, sdy += s[id[i]].y;
    sdx /= r - l + 1, sdy /= r - l + 1;
    for (int i = l; i <= r; i++)
        dx += sq(sdx - s[id[i]].x), dy += sq(sdy - s[id[i]].y);
    nth_element(id + l, id + mid, id + r + 1, dx > dy ? cmpx : cmpy);
    dim[id[mid]] = dx > dy;
    ls[id[mid]] = build(l, mid - 1);
    rs[id[mid]] = build(mid + 1, r);
    push_up(id[mid]);
    return id[mid];
}
inline void query(int l, int r, int x)
{
    if (l > r)
        return;
    int mid = l + r >> 1;
    ll tmp = sq(s[id[mid]].x - s[id[x]].x) + sq(s[id[mid]].y - s[id[x]].y);
    if (tmp > q.top())
        q.pop(), q.emplace(tmp);
    ll dl = dis(id[x], ls[id[mid]]), dr = dis(id[x], rs[id[mid]]);
    if (dl > q.top() && dr > q.top())
    {
        if (dl > dr)
        {
            query(l, mid - 1, x);
            if (dr > q.top())
                query(mid + 1, r, x);
        }
        else
        {
            query(mid + 1, r, x);
            if (dl > q.top())
                query(l, mid - 1, x);
        }
    }
    else
    {
        if (dl > q.top())
            query(l, mid - 1, x);
        if (dr > q.top())
            query(mid + 1, r, x);
    }
}
View Code

 


 

树链剖分

树链剖分(洛谷P3384)

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n, m, root, mod, a[N], head[N], to[N << 1], nxt[N << 1], tot;
int dep[N], fa[N], sz[N], son[N], id[N], val[N], top[N], cnt;
inline void link(int u, int v)
{
    to[tot] = v;
    nxt[tot] = head[u];
    head[u] = tot++;
}
namespace SegTree
{
    int t[N << 2], tag[N << 2];
    inline int ls(int p)
    {
        return p << 1;
    }
    inline int rs(int p)
    {
        return p << 1 | 1;
    }
    inline void push_up(int p)
    {
        t[p] = (t[ls(p)] + t[rs(p)]) % mod;
    }
    inline void f(int p, int l, int r, int k)
    {
        tag[p] += k;
        t[p] = (t[p] + k * (r - l + 1)) % mod;
    }
    inline void push_down(int p, int l, int r)
    {
        int mid = l + r >> 1;
        f(ls(p), l, mid, tag[p]);
        f(rs(p), mid + 1, r, tag[p]);
        tag[p] = 0;
    }
    inline void build(int p, int l, int r)
    {
        if (l == r)
        {
            t[p] = val[l] % mod;
            return;
        }
        int mid = l + r >> 1;
        build(ls(p), l, mid);
        build(rs(p), mid + 1, r);
        push_up(p);
    }
    inline void update(int p, int l, int r, int dl, int dr, int k)
    {
        if (dl <= l && r <= dr)
        {
            f(p, l, r, k);
            return;
        }
        push_down(p, l, r);
        int mid = l + r >> 1;
        if (dl <= mid)
            update(ls(p), l, mid, dl, dr, k);
        if (mid < dr)
            update(rs(p), mid + 1, r, dl, dr, k);
        push_up(p);
    }
    inline int query(int p, int l, int r, int qx, int qy)
    {
        if (qx <= l && r <= qy)
            return t[p];
        push_down(p, l, r);
        int res = 0, mid = l + r >> 1;
        if (qx <= mid)
            res = (res + query(ls(p), l, mid, qx, qy)) % mod;
        if (mid < qy)
            res = (res + query(rs(p), mid + 1, r, qx, qy)) % mod;
        return res;
    }
}
namespace HLD
{
    inline int rangeSum(int x, int y)
    {
        int res = 0;
        while (top[x] != top[y])
        {
            if (dep[top[x]] < dep[top[y]])
                swap(x, y);
            res = (res + SegTree::query(1, 1, n, id[top[x]], id[x])) % mod;
            x = fa[top[x]];
        }
        if (dep[x] > dep[y])
            swap(x, y);
        return (res + SegTree::query(1, 1, n, id[x], id[y])) % mod;
    }
    inline int treeSum(int x)
    {
        return SegTree::query(1, 1, n, id[x], id[x] + sz[x] - 1);
    }
    inline void rangeUpd(int x, int y, int k)
    {
        while (top[x] != top[y])
        {
            if (dep[top[x]] < dep[top[y]])
                swap(x, y);
            SegTree::update(1, 1, n, id[top[x]], id[x], k);
            x = fa[top[x]];
        }
        if (dep[x] > dep[y])
            swap(x, y);
        SegTree::update(1, 1, n, id[x], id[y], k);
    }
    inline void treeUpd(int x, int k)
    {
        SegTree::update(1, 1, n, id[x], id[x] + sz[x] - 1, k);
    }
}
inline void dfs1(int x, int f, int d)
{
    fa[x] = f;
    dep[x] = d;
    sz[x] = 1;
    int mx = 0;
    for (int i = head[x]; ~i; i = nxt[i])
        if (to[i] != f)
        {
            dfs1(to[i], x, d + 1);
            sz[x] += sz[to[i]];
            if (sz[to[i]] > mx)
            {
                mx = sz[to[i]];
                son[x] = to[i];
            }
        }
}
inline void dfs2(int x, int tp)
{
    id[x] = ++cnt;
    val[cnt] = a[x];
    top[x] = tp;
    if (!son[x])
        return;
    dfs2(son[x], tp);
    for (int i = head[x]; ~i; i = nxt[i])
        if (to[i] != fa[x] && to[i] != son[x])
            dfs2(to[i], to[i]); // new begin
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    memset(head, -1, sizeof(head));
    cin >> n >> m >> root >> mod;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    for (int i = 1, u, v; i < n; i++)
    {
        cin >> u >> v;
        link(u, v);
        link(v, u);
    }
    dfs1(root, 0, 1);
    dfs2(root, root);
    SegTree::build(1, 1, n);
    while (m--)
    {
        int op, x, y, k;
        cin >> op;
        switch (op)
        {
        case 1:
            cin >> x >> y >> k;
            HLD::rangeUpd(x, y, k % mod);
            break;
        case 2:
            cin >> x >> y;
            cout << HLD::rangeSum(x, y) << '\n';
            break;
        case 3:
            cin >> x >> k;
            HLD::treeUpd(x, k % mod);
            break;
        default:
            cin >> x;
            cout << HLD::treeSum(x) << '\n';
        }
    }
    return 0;
}
View Code

 


点分树

点分树(洛谷P6329)

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n, m, head[N], to[N << 1], nxt[N << 1], tot;
int a[N], g[N << 1][20], pos[N], dep[N], sz[N], f[N], cnt, minn, root;
bool vis[N];
vector<int> t[2][N];
inline void link(int u, int v)
{
    to[tot] = v;
    nxt[tot] = head[u];
    head[u] = tot++;
}
inline void dfs1(int x, int fa)
{
    g[++cnt][0] = x;
    pos[x] = cnt;
    for (int i = head[x]; ~i; i = nxt[i])
        if (to[i] != fa)
        {
            dep[to[i]] = dep[x] + 1;
            dfs1(to[i], x);
            g[++cnt][0] = x;
        }
}
inline void init()
{
    for (int i = 1; 1 << i <= cnt; i++)
        for (int j = 1; j + (1 << i) <= cnt; j++)
            g[j][i] = min(g[j][i - 1], g[j + (1 << i - 1)][i - 1]);
}
inline int tmin(int x, int y)
{
    return dep[x] < dep[y] ? x : y;
}
inline int dis(int x, int y)
{
    if (pos[x] > pos[y])
        swap(x, y);
    int l = pos[x], r = pos[y], k = log2(r - l + 1);
    int lca = tmin(g[l][k], g[r - (1 << k) + 1][k]);
    return dep[x] + dep[y] - (dep[lca] << 1);
}
inline int lowbit(int x)
{
    return x & -x;
}
inline void add(int p, int op, int x, int k)
{
    for (x++; x <= sz[p]; x += lowbit(x))
        t[op][p][x] += k;
}
inline int query(int p, int op, int x)
{
    int res = 0;
    for (x = min(x + 1, sz[p]); x; x -= lowbit(x))
        res += t[op][p][x];
    return res;
}
inline void getRoot(int x, int fa, int k)
{
    sz[x] = 1;
    int res = 0;
    for (int i = head[x]; ~i; i = nxt[i])
        if (to[i] != fa && !vis[to[i]])
        {
            getRoot(to[i], x, k);
            sz[x] += sz[to[i]];
            res = max(res, sz[to[i]]);
        }
    res = max(res, k - sz[x]);
    if (res < minn)
    {
        minn = res;
        root = x;
    }
}
inline void build(int x, int k)
{
    vis[x] = true;
    sz[x] = k;
    t[0][x].resize(sz[x] + 1);
    t[1][x].resize(sz[x] + 1);
    for (int i = head[x]; ~i; i = nxt[i])
        if (!vis[to[i]])
        {
            root = 0, minn = 1e9;
            getRoot(to[i], 0, sz[to[i]]);
            f[root] = x;
            build(root, sz[to[i]] + 1);
        }
}
inline void update(int x, int k)
{
    for (int i = x; i; i = f[i])
        add(i, 0, dis(x, i), k);
    for (int i = x; f[i]; i = f[i])
        add(i, 1, dis(x, f[i]), k);
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    memset(head, -1, sizeof(head));
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    for (int i = 1, u, v; i < n; i++)
    {
        cin >> u >> v;
        link(u, v);
        link(v, u);
    }
    dfs1(1, 0);
    init();
    root = 0, minn = 1e9;
    getRoot(1, 0, n);
    build(root, n);
    for (int i = 1; i <= n; i++)
        update(i, a[i]);
    int last = 0;
    while (m--)
    {
        int op, x, y;
        cin >> op >> x >> y;
        x ^= last, y ^= last;
        if (op)
            update(x, y - a[x]), a[x] = y;
        else
        {
            last = query(x, 0, y);
            for (int i = x; f[i]; i = f[i])
            {
                int tmp = dis(x, f[i]);
                if (y >= tmp)
                    last += query(f[i], 0, y - tmp) - query(i, 1, y - tmp);
            }
            cout << last << '\n';
        }
    }
    return 0;
}
View Code

 


分块

区间众数(洛谷P4168)

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 4e4 + 5;
struct node
{
    int val, id, x;
} a[N];
struct Point
{
    int num, cnt;
    inline Point(int _num = 0, int _cnt = 0)
    {
        num = _num, cnt = _cnt;
    }
} f[205][205];
int n, m, sq, tot, sum[205][N], tmp[N], initnum[N];
int len, num[N], L[N], R[N];
inline bool cmp1(const node &x, const node &y)
{
    return x.val < y.val;
}
inline bool cmp2(const node &x, const node &y)
{
    return x.id < y.id;
}
inline int query(int l, int r)
{
    Point res;
    if (num[r] - num[l] <= 2)
    {
        for (int i = l; i <= r; i++)
            tmp[a[i].x] = 0;
        for (int i = l; i <= r; i++)
        {
            tmp[a[i].x]++;
            if (tmp[a[i].x] > res.cnt || tmp[a[i].x] == res.cnt && a[i].x < res.num)
                res = (Point){a[i].x, tmp[a[i].x]};
        }
        return initnum[res.num];
    }
    res = f[num[l] + 1][num[r] - 1];
    for (int i = l; i <= min(r, R[num[l]]); i++)
        tmp[a[i].x] = sum[num[r] - 1][a[i].x] - sum[num[l]][a[i].x];
    for (int i = L[num[r]]; i <= r; i++)
        tmp[a[i].x] = sum[num[r] - 1][a[i].x] - sum[num[l]][a[i].x];
    for (int i = l; i <= min(r, R[num[l]]); i++)
    {
        tmp[a[i].x]++;
        if (tmp[a[i].x] > res.cnt || tmp[a[i].x] == res.cnt && a[i].x < res.num)
            res = (Point){a[i].x, tmp[a[i].x]};
    }
    for (int i = L[num[r]]; i <= r; i++)
    {
        tmp[a[i].x]++;
        if (tmp[a[i].x] > res.cnt || tmp[a[i].x] == res.cnt && a[i].x < res.num)
            res = (Point){a[i].x, tmp[a[i].x]};
    }
    return initnum[res.num];
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        cin >> a[i].val, a[i].id = i;
    sort(a + 1, a + 1 + n, cmp1);
    for (int i = 1; i <= n; i++)
        a[i].x = a[i].val == a[i - 1].val ? tot : ++tot, initnum[a[i].x] = a[i].val;
    sort(a + 1, a + 1 + n, cmp2);
    sq = sqrt(n);
    for (int i = 1; i <= n; i++)
        num[i] = (i - 1) / sq + 1;
    for (int i = 1; (i - 1) * sq <= n; i++)
        L[i] = (i - 1) * sq + 1, R[i] = min(i * sq, n), len = i;
    for (int i = 1; i <= len; i++)
        for (int j = 1; j <= R[i]; j++)
            sum[i][a[j].x]++;
    for (int i = 1; i <= len; i++)
    {
        memset(tmp, 0, sizeof(tmp));
        Point res;
        for (int j = i; j <= len; j++)
        {
            for (int k = L[j]; k <= R[j]; k++)
            {
                tmp[a[k].x]++;
                if (tmp[a[k].x] > res.cnt || tmp[a[k].x] == res.cnt && a[k].x < res.num)
                    res = (Point){a[k].x, tmp[a[k].x]};
            }
            f[i][j] = res;
        }
    }
    int last = 0;
    while (m--)
    {
        int l, r;
        cin >> l >> r;
        l = (l + last - 1) % n + 1, r = (r + last - 1) % n + 1;
        if (l > r)
            swap(l, r);
        last = query(l, r);
        cout << last << '\n';
    }
    return 0;
}
View Code

 


自动机

AC自动机(ACAM)

queue<int> q;
struct ACAM
{
    int t[N][26], fail[N], tot, tag[N], stk[N], pos[N], tail;
    inline void insert(string s)
    {
        int cur = 0;
        for (char c : s)
        {
            c -= 'a';
            if (!t[cur][c])
                t[cur][c] = ++tot;
            cur = t[cur][c];
        }
        tag[cur] += s.size();
    }
    inline void build()
    {
        for (int i = 0; i < 26; i++)
            if (t[0][i])
            {
                fail[t[0][i]] = 0;
                q.emplace(t[0][i]);
            }
        while (!q.empty())
        {
            int x = q.front();
            q.pop();
            for (int i = 0; i < 26; i++)
                if (t[x][i])
                {
                    fail[t[x][i]] = t[fail[x]][i];
                    q.emplace(t[x][i]);
                }
                else
                    t[x][i] = t[fail[x]][i];
        }
    }
};
View Code

 

回文自动机(PAM)

struct PAM
{
    int len[N], num[N], fail[N], t[N][26], tot = 1;
    string s;
    inline int getFail(int x, int i)
    {
        while (i - len[x] - 1 < 0 || s[i] != s[i - len[x] - 1])
            x = fail[x];
        return x;
    }
    inline void build()
    {
        int cur = 0;
        fail[0] = 1, len[1] = -1;
        for (int i = 0; i < s.size(); i++)
        {
            s[i] -= 'A';
            int pos = getFail(cur, i);
            if (!t[pos][s[i]])
            {
                fail[++tot] = t[getFail(fail[pos], i)][s[i]];
                t[pos][s[i]] = tot;
                len[tot] = len[pos] + 2;
            }
            cur = t[pos][s[i]];
            num[cur]++;
        }
        for (int i = tot; i >= 2; i--)
            num[fail[i]] += num[i];
    }
};
View Code

 

后缀自动机(SAM)

struct SAM
{
    int tot, last, len[N], fa[N], t[N][26];
    inline SAM()
    {
        last = tot = 0;
        fa[0] = -1;
    }
    inline void insert(char c)
    {
        c -= 'a';
        int cur = ++tot;
        len[cur] = len[last] + 1;
        int p = last;
        last = cur;
        while (~p && !t[p][c])
            t[p][c] = cur, p = fa[p];
        if (!~p)
        {
            fa[cur] = 0;
            return;
        }
        int x = t[p][c];
        if (len[p] + 1 == len[x])
            fa[cur] = x;
        else
        {
            len[++tot] = len[p] + 1;
            fa[tot] = fa[x];
            memcpy(t[tot], t[x], sizeof(t[x]));
            while (~p && t[p][c] == x)
                t[p][c] = tot, p = fa[p];
            fa[x] = fa[cur] = tot;
        }
    }
}
View Code

 

广义后缀自动机(广义SAM)

#include <bits/stdc++.h>
using namespace std;
const int N = 2e6 + 5;
string s;
long long ans;
int n;
struct SAM
{
    int tot, last, fa[N], len[N], t[N][26];
    inline SAM()
    {
        tot = last = 0;
        fa[0] = -1;
    }
    inline void insert(char c)
    {
        c -= 'a';
        int cur = ++tot;
        len[cur] = len[last] + 1;
        int p = last;
        while (~p && !t[p][c])
            t[p][c] = cur, p = fa[p];
        last = cur;
        if (!~p)
        {
            fa[cur] = 0;
            ans += len[cur] - len[0];
            return;
        }
        int x = t[p][c];
        if (len[x] == len[p] + 1)
            fa[cur] = x;
        else
        {
            len[++tot] = len[p] + 1;
            fa[tot] = fa[x];
            memcpy(t[tot], t[x], sizeof(t[x]));
            while (~p && t[p][c] == x)
                t[p][c] = tot, p = fa[p];
            fa[x] = fa[cur] = tot;
        }
        ans += len[cur] - len[fa[cur]];
    }
} sam;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        string s;
        cin >> s;
        sam.last = 0;
        for (char c : s)
            sam.insert(c);
    }
    cout << ans;
    return 0;
}
View Code

 

 


 

线性基

普通

ll p[70];
inline void build(ll x, ll k)
{
    for (int i = 65; i >= 0; i--)
        if (x >> i & 1)
        {
            if (!p[i])
            {
                p[i] = x;
                break;
            }
            x ^= p[i];
        }
}
View Code

 

前缀版

struct Prefix_Hamel
{
    ll p[65];
    int pos[65];
    inline void insert(ll x, int id)
    {
        for (int i = 60; i >= 0; i--)
            if (x >> i & 1)
            {
                if (!p[i])
                {
                    p[i] = x, pos[i] = id;
                    break;
                }
                else if (pos[i] < id)
                    swap(pos[i], id), swap(p[i], x);
                x ^= p[i];
            }
    }
    inline ll query(int l)
    {
        ll res = 0;
        for (int i = 60; i >= 0; i--)
            if (pos[i] >= l)
                res = max(res, res ^ p[i]);
        return res;
    }
}
View Code

 

通用版(雾

struct Hamel
{
    ll p[65];
    int pos[65];
    inline void insert(ll x, int id = 0)
    {
        for (int i = 60; i >= 0; i--)
        {
            if (x >> i & 1)
            {
                if (!p[i])
                {
                    p[i] = x, pos[i] = id;
                    break;
                }
                else if (id > pos[i])
                    swap(pos[i], id), swap(p[i], x);
                x ^= p[i];
            }
        }
    }
    inline ll query(int l = -1)
    {
        ll res = 0;
        for (int i = 60; i >= 0; i--)
            if (!~l || pos[i] >= l)
                res = max(res, res ^ p[i]);
        return res;
    }
}
View Code

 


后缀数据结构

后缀数组(SA)

int n, m, c[N], sa[N], rk[N], id[N], prerk[N];
inline void build()
{
    for (int i = 1; i <= n; i++)
        c[rk[i] = s[i]]++;
    for (int i = 1; i <= m; i++)
        c[i] += c[i - 1];
    for (int i = n; i; i--)
        sa[c[rk[i]]--] = i;
    for (int i = 1, p; i <= n; i <<= 1)
    {
        p = 0;
        for (int j = n - i + 1; j <= n; j++) // second
            id[++p] = j;
        for (int j = 1; j <= n; j++) // first
            if (sa[j] > i)
                id[++p] = sa[j] - i;
        memset(c, 0, sizeof(c));
        for (int j = 1; j <= n; j++)
            c[rk[j]]++;
        for (int j = 1; j <= m; j++)
            c[j] += c[j - 1];
        for (int j = n; j; j--)
            sa[c[rk[id[j]]]--] = id[j];
        memcpy(prerk, rk, sizeof(rk));
        p = 0;
        for (int j = 1; j <= n; j++)
            rk[sa[j]] = prerk[sa[j]] == prerk[sa[j - 1]] && prerk[sa[j] + i] == prerk[sa[j - 1] + i] ? p : ++p;
        if (p == n)
            break;
        m = p;
    }
}
View Code

 

后缀自动机(SAM)

string s;
struct SAM
{
    int tot, last, len[N], fa[N], t[N][26];
    inline SAM()
    {
        last = tot = 0;
        fa[0] = -1;
    }
    inline void insert(char c)
    {
        c -= 'a';
        int cur = ++tot;
        len[cur] = len[last] + 1;
        int p = last;
        last = cur;
        while (~p && !t[p][c])
            t[p][c] = cur, p = fa[p];
        if (!~p)
        {
            fa[cur] = 0;
            return;
        }
        int x = t[p][c];
        if (len[p] + 1 == len[x])
            fa[cur] = x;
        else
        {
            len[++tot] = len[p] + 1;
            fa[tot] = fa[x];
            memcpy(t[tot], t[x], sizeof(t[x]));
            while (~p && t[p][c] == x)
                t[p][c] = tot, p = fa[p];
            fa[x] = fa[cur] = tot;
        }
    }
}
View Code

 

后缀数组扩展(求两串LCP)

struct Suffix_Array
{
    string s;
    int n, m, sa[N], rk[N], height[N], prerk[N], c[N], id[N];
    int st[N][25];
    inline void build()
    {
        m = 'z';
        memset(c, 0, sizeof(c));
        memset(rk, 0, sizeof(rk));
        for (int i = 1; i <= n; i++)
            c[rk[i] = s[i - 1]]++;
        for (int i = 1; i <= m; i++)
            c[i] += c[i - 1];
        for (int i = n; i; i--)
            sa[c[rk[i]]--] = i;
        for (int i = 1, p; i < n; i <<= 1)
        {
            p = 0;
            for (int j = n - i + 1; j <= n; j++)
                id[++p] = j;
            for (int j = 1; j <= n; j++)
                if (sa[j] > i)
                    id[++p] = sa[j] - i;
            memset(c, 0, sizeof(c));
            for (int j = 1; j <= n; j++)
                c[rk[j]]++;
            for (int j = 1; j <= m; j++)
                c[j] += c[j - 1];
            for (int j = n; j; j--)
                sa[c[rk[id[j]]]--] = id[j];
            memcpy(prerk, rk, sizeof(rk));
            p = 0;
            for (int j = 1; j <= n; j++)
                rk[sa[j]] = prerk[sa[j]] == prerk[sa[j - 1]] && prerk[sa[j] + i] == prerk[sa[j - 1] + i] ? p : ++p;
            if (p == n)
                break;
            m = p;
        }
    }
    inline void getHeight()
    {
        for (int i = 1, k = 0; i <= n; i++)
        {
            if (k)
                k--;
            while (s[i + k - 1] == s[sa[rk[i] - 1] + k - 1])
                k++;
            height[rk[i]] = k;
        }
    }
    inline void initST()
    {
        for (int i = 1; i <= n; i++)
            st[i][0] = height[i];
        for (int i = 1; i <= 22; i++)
            for (int j = 1; j + (1 << i) - 1 <= n; j++)
                st[j][i] = min(st[j][i - 1], st[j + (1 << i - 1)][i - 1]);
    }
    inline int query(int l, int r)
    {
        l = rk[l], r = rk[r];
        if (l > r)
            swap(l, r);
        l++;
        int k = log2(r - l + 1);
        return min(st[l][k], st[r - (1 << k) + 1][k]);
    }
}
View Code

 


左偏树

左偏树

int L[N], R[N], dep[N], val[N];
inline int Merge(int x, int y)
{
    if (!x || !y)
        return x + y;
    if (val[x] > val[y])
        swap(x, y);
    R[x] = Merge(R[x], y);
    if (dep[L[x]] < dep[R[x]])
        swap(L[x], R[x]);
    dep[x] = dep[R[x]] + 1;
    return x;
}
View Code

 


并查集(打开有惊喜)

并查集

struct DSU
{
private:
    int ch[N][2], fa[N];
    bool rev[N];
    inline bool isrt(int x)
    {
        return ch[fa[x]][0] == x || ch[fa[x]][1] == x;
    }
    inline void reverse(int x)
    {
        swap(ch[x][0], ch[x][1]);
        rev[x] ^= 1;
    }
    inline void push_down(int x)
    {
        if (rev[x])
        {
            if (ch[x][0])
                reverse(ch[x][0]);
            if (ch[x][1])
                reverse(ch[x][1]);
            rev[x] = 0;
        }
    }
    inline void rotate(int x)
    {
        int y = fa[x], z = fa[y], k = ch[y][1] == x;
        if (isrt(y))
            ch[z][ch[z][1] == y] = x;
        fa[x] = z;
        fa[ch[y][k] = ch[x][k ^ 1]] = y;
        fa[ch[x][k ^ 1] = y] = x;
    }
    int stk[N];
    inline void splay(int x)
    {
        int top = 1, cur = x;
        stk[1] = cur;
        while (isrt(cur))
            stk[++top] = (cur = fa[cur]);
        while (top)
            push_down(stk[top--]);
        while (isrt(x))
        {
            int y = fa[x], z = fa[y];
            if (isrt(y))
                rotate((ch[y][0] == x) ^ (ch[z][0] == y) ? x : y);
            rotate(x);
        }
    }
    inline void access(int x)
    {
        for (int y = 0; x; y = x, x = fa[x])
            splay(x), ch[x][1] = y;
    }
    inline void makert(int x)
    {
        access(x);
        splay(x);
        reverse(x);
    }
    inline void split(int x, int y)
    {
        makert(x);
        access(y);
        splay(y);
    }

public:
    inline void link(int x, int y)
    {
        makert(x);
        fa[x] = y;
    }
    inline void cut(int x, int y)
    {
        split(x, y);
        fa[x] = ch[y][0] = 0;
    }
    inline int find(int x)
    {
        access(x);
        splay(x);
        push_down(x);
        while (ch[x][0])
            x = ch[x][0], push_down(x);
        splay(x);
        return x;
    }
};
View Code

 

 

posted @ 2022-08-12 18:57  creation_hy  阅读(503)  评论(0编辑  收藏  举报