代码模板

DS

// 372647698
// 372648762 (KruskalDSU rollback)
// 372649357 (HLD ord版)
// 375447272 (treap )
// 375466130 (rebuilt segtree)
// 375832338 (advance lazysegtree)
// 378264476(fastscan seg BITMin)
// 378266021 (coverTree oneTree)
// 367936311 enum
// 367727170 kmp
// 367086731 Matrix power
// https://codeforces.com/contest/1902/submission/235594491 Basic Xor

随机数

// https://codeforces.com/contest/2219/submission/371036839

中心扩展

// 2022-06-27 11:35:45
// https://codeforces.com/contest/1519/submission/161927828

#include <bits/stdc++.h>

using i64 = long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int n;
    std::cin >> n;
    
    std::vector<int> a(n), b(n);
    i64 sum = 0;
    for (int i = 0; i < n; i++) {
        std::cin >> a[i];
    }
    for (int i = 0; i < n; i++) {
        std::cin >> b[i];
        sum += 1LL * a[i] * b[i];
    }
    
    i64 ans = sum;
    for (int s = 0; s <= 2 * n - 2; s++) {
        i64 cur = sum;
        for (int i = s / 2; i >= 0 && s - i < n; i--) {
            cur -= 1LL * a[i] * b[i] + 1LL * a[s - i] * b[s - i];
            cur += 1LL * a[i] * b[s - i] + 1LL * a[s - i] * b[i];
            ans = std::max(ans, cur);
        }
    }
    
    std::cout << ans << "\n";
    
    return 0;
}

/*
    for (int i = 0; i < 2 * n - 1; ++i) {
        int l = i / 2, r = (i + 1) / 2;
        i64 sum = s;
        for (; l >= 0 && r < n; --l, ++r) {
            sum += 1LL * (a[r] - a[l]) * (b[l] - b[r]);
            ans = std::max(ans, sum);
        }
    }
*/

线段树合并

// 2026-04-09 19:31:06
// https://codeforces.com/contest/700/submission/370450479
// http://codeforces.com/contest/2219/submission/371006515
#include <bits/stdc++.h>

using i64 = long long;
using u64 = unsigned long long;
using u32 = unsigned;

using u128 = unsigned __int128;
using i128 = __int128;

namespace rgs = std::ranges;

struct SAM {
    static constexpr int ALPHABET_SIZE = 26;
    struct Node {
        int len;
        int link;
        std::array<int, ALPHABET_SIZE> next;
        Node() : len{}, link{}, next{} {}
    };
    std::vector<Node> t;
    SAM() {
        init();
    }
    void init() {
        t.assign(2, Node());
        t[0].next.fill(1);
        t[0].len = -1;
    }
    int newNode() {
        t.emplace_back();
        return t.size() - 1;
    }
    int extend(int p, int c) {
        if (t[p].next[c]) {
            int q = t[p].next[c];
            if (t[q].len == t[p].len + 1) {
                return q;
            }
            int r = newNode();
            t[r].len = t[p].len + 1;
            t[r].link = t[q].link;
            t[r].next = t[q].next;
            t[q].link = r;
            while (t[p].next[c] == q) {
                t[p].next[c] = r;
                p = t[p].link;
            }
            return r;
        }
        int cur = newNode();
        t[cur].len = t[p].len + 1;
        while (!t[p].next[c]) {
            t[p].next[c] = cur;
            p = t[p].link;
        }
        t[cur].link = extend(p, c);
        return cur;
    }
    int extend(int p, char c, char offset = 'a') {
        return extend(p, c - offset);
    }
    
    int next(int p, int x) {
        return t[p].next[x];
    }
    
    int next(int p, char c, char offset = 'a') {
        return next(p, c - offset);
    }
    
    int link(int p) {
        return t[p].link;
    }
    
    int len(int p) {
        return t[p].len;
    }
    
    int size() {
        return t.size();
    }
};

constexpr int N = 200000 * 2 * 20;

struct Node {
    int l;
    int r;
    int sum;
};
std::vector<Node> t(N);

int tot = 0;
int add(int l, int r, int x) {
    int o = ++tot;
    t[o].sum = 1;
    if (r - l == 1) {
        return o;
    }
    int m = (l + r) / 2;
    if (x < m) {
        t[o].l = add(l, m, x);
    } else {
        t[o].r = add(m, r, x);
    }
    return o;
}

int merge(int p, int q) {
    if (!p) {
        return q;
    }
    if (!q) {
        return p;
    }
    int o = ++tot;
    t[o].sum = t[p].sum + t[q].sum;
    t[o].l = merge(t[p].l, t[q].l);
    t[o].r = merge(t[p].r, t[q].r);
    return o;
}

int query(int o, int l, int r, int x, int y) {
    if (!o || l >= y || r <= x) {
        return 0;
    }
    if (l >= x && r <= y) {
        return t[o].sum;
    }
    int m = (l + r) / 2;
    return query(t[o].l, l, m, x, y) + query(t[o].r, m, r, x, y);
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int n;
    std::cin >> n;
    
    std::string s;
    std::cin >> s;
    
    SAM sam;
    int p = 1;
    std::vector<int> ends(n + 1);
    ends[0] = 1;
    for (int i = 1; i <= n; i++) {
        p = sam.extend(p, s[i - 1]);
        ends[i] = p;
    }
    
    std::vector<std::vector<int>> adj(sam.size());
    std::vector<int> any(sam.size());
    
    for (int i = 2; i < sam.size(); i++) {
        adj[sam.link(i)].push_back(i);
    }
    
    std::vector<int> rt(sam.size());
    for (int i = 0; i <= n; i++) {
        rt[ends[i]] = add(0, n + 1, i);
        any[ends[i]] = i;
    }
    
    [&](this auto &&self, int x) -> void {
        for (auto y : adj[x]) {
            self(y);
            rt[x] = merge(rt[x], rt[y]);
        }
    } (1);
    
    std::vector<int> dp(sam.size());
    std::vector<int> g(sam.size());
    [&](this auto &&self, int x) -> void {
        for (auto y : adj[x]) {
            int l = any[y] - sam.len(y) + sam.len(g[x]);
            int r = any[y];
            
            if (query(rt[x], 0, n + 1, l, r)) {
                dp[y] = dp[x] + 1;
                g[y] = y;
            } else {
                dp[y] = dp[x];
                g[y] = g[x];
            }
            
            self(y);
        }
    } (1);
    
    int ans = rgs::max(dp);
    
    std::cout << ans << "\n";
    
    return 0;
}

平衡树

fhq-treap

#include <bits/stdc++.h>

constexpr int L = 4E6 + 5;
constexpr int MINV = -1E7 - 5;
constexpr int MAXV = 1E7 + 5;

std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count());

struct Node {
    int l, r;
    int siz = 0;
    int cnt = 0;
    int w;
    int x;
} node[L];

void push(int t) {}
void pull(int t) {
    node[t].siz = node[node[t].l].siz + node[node[t].r].siz + node[t].cnt;
}

std::pair<int, int> split(int t, int x) {
    if (!t) {
        return {t, t};
    }
    push(t);
    if (x < node[t].x) {
        auto [l, r] = split(node[t].l, x);
        node[t].l = r;
        pull(t);
        return {l, t};
    } else {
        auto [l, r] = split(node[t].r, x);
        node[t].r = l;
        pull(t);
        return {t, r};
    }
}

int merge(int l, int r) {
    if (!l || !r) {
        return l ? l : r;
    }
    if (node[l].w < node[r].w) {
        node[l].r = merge(node[l].r, r);
        pull(l);
        return l;
    } else {
        node[r].l = merge(l, node[r].l);
        pull(r);
        return r;
    }
}

int newNode(int x) {
    static int tot = 0;
    ++tot;
    node[tot].x = x;
    node[tot].w = rng();
    return tot;
}

void insert(int &t, int x) {
    auto [l, u] = split(t, x - 1);
    auto [v, r] = split(u, x);

    if (!v) {
        v = newNode(x);
    }
    if (x == node[v].x) {
        ++node[v].cnt;
        pull(v);
    }

    t = merge(l, merge(v, r));
}


void erase(int &t, int x) {
    auto [l, u] = split(t, x - 1);
    auto [v, r] = split(u, x);
    if (node[v].cnt > 1) {
        --node[v].cnt;
        pull(v);
    } else {
        v = 0;
    }
    t = merge(l, merge(v, r));
}

int rank(int t, int x) {
    int res = 0;
    while (t) {
        if (node[t].x < x) {
            res += node[node[t].l].siz + node[t].cnt;
            t = node[t].r;
        } else {
            t = node[t].l;
        }
    }
    return res;
}

int get(int t, int x) {
    while (t) {
        int l = node[node[t].l].siz;
        if (l <= x && x < l + node[t].cnt) {
            return node[t].x;
        }
        if (x < l) {
            t = node[t].l;
        } else {
            x -= l + node[t].cnt;
            t = node[t].r;
        }
    }
    return 0;
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n;
    std::cin >> n;

    int t = 0;

    while (n--) {
        int op, x;
        std::cin >> op >> x;

        if (op == 1) {
            insert(t, x);
        } else if (op == 2) {
            erase(t, x);
        } else if (op == 3) {
            std::cout << rank(t, x) + 1 << "\n";
        } else if (op == 4) {
            std::cout << get(t, x - 1) << "\n";
        } else if (op == 5) {
            int k = rank(t, x);
            std::cout << get(t, k - 1) << "\n";
        } else {
            int k = rank(t, x + 1);
            std::cout << get(t, k) << "\n";
        }
    }
}

pb_ds

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

template <class T>
using ordered_set = __gnu_pbds::tree<
    std::pair<T, int>,
    __gnu_pbds::null_type,
    std::less<>,
    __gnu_pbds::rb_tree_tag,
    // __gnu_pbds::splay_tree_tag,
    __gnu_pbds::tree_order_statistics_node_update
>;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n;
    std::cin >> n;

    int idx = 0;
    ordered_set<int> t;

    while (n--) {
        int op, x;
        std::cin >> op >> x;

        if (op == 1) {
            t.insert({x, idx++});
        } else if (op == 2) {
            auto it = t.lower_bound({x, -1});
            if (it != t.end() && it->first == x) {
                t.erase(it);
            }
        } else if (op == 3) {
            std::cout << t.order_of_key({x, -1}) + 1 << "\n";
        } else if (op == 4) {
            std::cout << t.find_by_order(x - 1)->first << "\n";
        } else if (op == 5) {
            // int k = t.order_of_key({x, -1}) - 1;
            // auto it = t.find_by_order(k);
            auto it = std::prev(t.lower_bound({x, -1}));
            std::cout << it->first << "\n";
        } else {
            // int k = t.order_of_key({x + 1, -1});
            // auto it = t.find_by_order(k);
            auto it = t.lower_bound({x + 1, -1});
            std::cout << it->first << "\n";
        }
    }
}

动态开点线段树

#include <bits/stdc++.h>

constexpr int L = 4E6 + 5;
constexpr int MINV = -1E7 - 5;
constexpr int MAXV = 1E7 + 5;

struct Node {
    int l, r;
    int cnt = 0;
    int x;
} node[L];

int newNode(int t = 0) {
    static int tot = 0;
    ++tot;
    node[tot] = node[t];
    return tot;
}

void add(int &p, int l, int r, int x, int t = 1) {
    if (!p) {
        p = newNode(p);
    }
    node[p].cnt += t;
    if (r - l == 1) {
        return;
    }
    int m = (r + l) / 2;
    if (x < m) {
        add(node[p].l, l, m, x, t);
    } else {
        add(node[p].r, m, r, x, t);
    }
}

void insert(int &t, int x) {
    return add(t, MINV, MAXV, x);
}

void erase(int &t, int x) {
    return add(t, MINV, MAXV, x, -1);
}

int rank(int t, int l, int r, int x) {
    if (!t || r - l == 1) {
        return 0;
    }
    int m = (r + l) / 2;
    if (x < m) {
        return rank(node[t].l, l, m, x);
    }
    return node[node[t].l].cnt + rank(node[t].r, m, r, x);
}

int rank(int t, int x) {
    return rank(t, MINV, MAXV, x);
}

int get(int p, int l, int r, int x) {
    if (r - l == 1) {
        return l;
    }
    int m = (r + l) / 2;
    int t = node[node[p].l].cnt;
    if (x < t) {
        return get(node[p].l, l, m, x);
    }
    return get(node[p].r, m, r, x - t);
}

int get(int t, int x) {
    return get(t, MINV, MAXV, x);
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n;
    std::cin >> n;

    int t = 0;

    while (n--) {
        int op, x;
        std::cin >> op >> x;

        if (op == 1) {
            insert(t, x);
        } else if (op == 2) {
            erase(t, x);
        } else if (op == 3) {
            std::cout << rank(t, x) + 1 << "\n";
        } else if (op == 4) {
            std::cout << get(t, x - 1) << "\n";
        } else if (op == 5) {
            int k = rank(t, x);
            std::cout << get(t, k - 1) << "\n";
        } else {
            int k = rank(t, x + 1);
            std::cout << get(t, k) << "\n";
        }
    }
}

splay

#include <bits/stdc++.h>

constexpr int N = 100000 + 5;
constexpr int INF = std::numeric_limits<int>::max();

struct Node {
    int ch[2], p;
    int v, cnt, siz;
} nodes[N];

int root, tot;

int newNode(int x) {
    int u = ++tot;
    nodes[u].v = x;
    // nodes[u].cnt = nodes[u].siz = 1;
    return u;
}

void pull(int u) {
    nodes[u].siz = nodes[nodes[u].ch[0]].siz + nodes[nodes[u].ch[1]].siz + nodes[u].cnt;
}

int pos(int u) {
    return nodes[nodes[u].p].ch[1] == u;
}

void rotate(int u) {
    int p = nodes[u].p, g = nodes[p].p;
    int k = pos(u);
    nodes[g].ch[nodes[g].ch[1] == p] = u;
    nodes[u].p = g;
    nodes[p].ch[k] = nodes[u].ch[k ^ 1];
    nodes[nodes[u].ch[k ^ 1]].p = p;
    nodes[u].ch[k ^ 1] = p;
    nodes[p].p = u;
    pull(p);
    pull(u);
}

void splay(int u) {
    while (nodes[u].p) {
        int p = nodes[u].p;
        if (nodes[p].p) {
            rotate(pos(u) == pos(p) ? p : u);
        }
        rotate(u);
    }
    root = u;
}

void insert(int &t, int x, int p = 0) {
    if (!t) {
        t = newNode(x);
        nodes[t].p = p;
    }
    if (nodes[t].v == x) {
        ++nodes[t].cnt;
        pull(t);
        splay(t);
        return;
    }
    if (x < nodes[t].v) {
        insert(nodes[t].ch[0], x, t);
    } else {
        insert(nodes[t].ch[1], x, t);
    }
}

int nth(int k) {
    int u = root;
    while (u) {
        int l = nodes[nodes[u].ch[0]].siz;
        if (k < l) {
            u = nodes[u].ch[0];
        } else if (k < l + nodes[u].cnt) {
            splay(u);
            return nodes[u].v;
        } else {
            k -= l + nodes[u].cnt;
            u = nodes[u].ch[1];
        }
    }
    return 0;
}

int rank(int x) {
    int u = root;
    int res = 0;
    int lst = u;
    while (u) {
        lst = u;
        if (nodes[u].v < x) {
            res += nodes[nodes[u].ch[0]].siz + nodes[u].cnt;
            u = nodes[u].ch[1];
        } else {
            u = nodes[u].ch[0];
        }
    }
    splay(lst);
    return res;
}

void del(int t, int x) {
    if (nodes[t].v != x) {
        return del(nodes[t].ch[nodes[t].v < x], x);
    }
    splay(t);
    if (nodes[t].cnt > 1) {
        --nodes[t].cnt;
        pull(t);
        return;
    }
    int l = nodes[t].ch[0], r = nodes[t].ch[1];
    if (!l || !r) {
        root = l | r;
        nodes[root].p = 0;
        return;
    }
    nodes[l].p = nodes[r].p = 0;
    root = l;
    int p = l;
    while (nodes[p].ch[1]) {
        p = nodes[p].ch[1];
    }
    splay(p);
    nodes[root].ch[1] = r;
    nodes[r].p = root;
    pull(root);
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n;
    std::cin >> n;
    
    while (n--) {
        int op, x;
        std::cin >> op >> x;
        if (op == 1) {
            insert(root, x);
        } else if (op == 2) {
            del(root, x);
        } else if (op == 3) {
            std::cout << rank(x) + 1 << '\n';
        } else if (op == 4) {
            std::cout << nth(x - 1) << "\n";
        } else if (op == 5) {
            int k = rank(x);
            std::cout << nth(k - 1) << "\n";
        } else {
            int k = rank(x + 1);
            std::cout << nth(k) << "\n";
        }
    }
}

字符串哈希

#include <bits/stdc++.h>

using i64 = long long;

struct Hash {
    static constexpr int N = 2;
    static constexpr std::array<i64, N> P{1000000007LL, 1000000009LL};
    static constexpr i64 B = 13331;

    std::array<i64, N> x{};

    constexpr Hash() = default;

    constexpr Hash(i64 v) {
        for (int j = 0; j < N; ++j) {
            x[j] = (v % P[j] + P[j]) % P[j];
        }
    }

    constexpr Hash &operator+=(const Hash &h) & {
        for (int j = 0; j < N; ++j) {
            x[j] = (x[j] + h.x[j]) % P[j];
        }
        return *this;
    }

    constexpr Hash &operator-=(const Hash &h) & {
        for (int j = 0; j < N; ++j) {
            x[j] = (x[j] - h.x[j] + P[j]) % P[j];
        }
        return *this;
    }

    constexpr Hash &operator*=(const Hash &h) & {
        for (int j = 0; j < N; ++j) {
            x[j] = x[j] * h.x[j] % P[j];
        }
        return *this;
    }

    friend constexpr Hash operator+(Hash a, const Hash &b) {
        return a += b;
    }

    friend constexpr Hash operator-(Hash a, const Hash &b) {
        return a -= b;
    }

    friend constexpr Hash operator*(Hash a, const Hash &b) {
        return a *= b;
    }

    // friend constexpr bool operator==(const Hash &a, const Hash &b) {
    //     return a.x == b.x;
    // }
    // friend constexpr bool operator<(const Hash &a, const Hash &b) {
    //     return a.x < b.x;
    // }
    // friend constexpr std::strong_ordering operator<=>(const Hash &a, const Hash &b) {
    //     return a.x <=> b.x;
    // }

    friend constexpr bool operator==(const Hash &a, const Hash &b) = default;
    friend constexpr auto operator<=>(const Hash &a, const Hash &b) = default;
};

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int m, q;
    std::cin >> m >> q;

    std::string t;
    std::cin >> t;

    std::vector<Hash> p(m + 1);
    std::vector<Hash> h(m + 1);

    p[0] = 1;

    for (int i = 0; i < m; ++i) {
        p[i + 1] = p[i] * Hash::B;
    }
    for (int i = 0; i < m; ++i) {
        h[i + 1] = h[i] * Hash::B + t[i];
    }

    auto get = [&](int l, int r) -> Hash { return h[r] - h[l] * p[r - l]; };

    while (q--) {
        int l1, r1, l2, r2;
        std::cin >> l1 >> r1 >> l2 >> r2;
        --l1, --l2;

        std::cout << (get(l1, r1) == get(l2, r2) ? "Yes" : "No") << "\n";
    }
}

快排

sort

#include <bits/stdc++.h>

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int n;
    std::cin >> n;
    
    std::vector<int> a(n);
    for (auto &x : a) {
        std::cin >> x;
    }
    
    auto partition = [&](int l, int r, int x) -> std::pair<int, int> {
        int i = l;
        while (i < r) {
            if (a[i] > x) {
                std::swap(a[i], a[--r]);
            } else if (a[i] < x) {
                std::swap(a[i++], a[l++]);
            } else {
                ++i;
            }
        }
        return {l, r};
    };
    
    auto sort = [&](auto &&self, int l, int r) -> void {
        if (r - l <= 1) {
            return;
        }
        int x = a[(l + r) / 2];
        
        auto [L, R] = partition(l, r, x);
        
        self(self, l, L);
        self(self, R, r);
    };
    sort(sort, 0, n);
    
    for (auto x : a) {
        std::cout << x << " ";
    }
}

nth

#include <bits/stdc++.h>

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int n, k;
    std::cin >> n >> k;
    --k;
    
    std::vector<int> a(n);
    for (auto &x : a) {
        std::cin >> x;
    }
    
    auto partition = [&](int l, int r, int x) -> std::pair<int, int> {
        int i = l;
        while (i < r) {
            if (a[i] > x) {
                std::swap(a[i], a[--r]);
            } else if (a[i] < x) {
                std::swap(a[i++], a[l++]);
            } else {
                ++i;
            }
        }
        return {l, r};
    };
    
    auto nth = [&](int l, int r, int k) -> void {
        while (r - l > 1) {
            int x = a[(l + r) / 2];
            
            auto [L, R] = partition(l, r, x);
            
            if (k < L) {
                r = L;
            } else if (R <= k) {
                l = R;
            } else {
                break;
            }
        }
    };
    nth(0, n, k);
    
    std::cout << a[k];
}

树套树

#include <bits/stdc++.h>

using i64 = long long;

constexpr int N = 1E8 + 5;
constexpr int L = 6E7 + 5;

struct Node {
    int l = 0, r = 0;
    int cnt = 0;
} node[L];

int tot = 0;
int newNode() {
    return ++tot;
}

void add(int &p, int l, int r, int x, int v) {
    if (!p) {
        p = newNode();
    }
    node[p].cnt += v;
    if (r - l == 1) {
        return;
    }
    int m = (l + r) / 2;
    if (x < m) {
        add(node[p].l, l, m, x, v);
    } else {
        add(node[p].r, m, r, x, v);
    }
}

int query(std::vector<int> &&t1, std::vector<int> &&t2, int l, int r, int k) {
    if (r - l == 1) {
        return 0;
    }
    int m = (l + r) / 2;
    if (k < m) {
        for (auto &t : t1) {
            t = node[t].l;
        }
        for (auto &t : t2) {
            t = node[t].l;
        }
        return query(std::move(t1), std::move(t2), l, m, k);
    } else {
        int s = 0;
        for (auto &t : t1) {
            s -= node[node[t].l].cnt;
            t = node[t].r;
        }
        for (auto &t : t2) {
            s += node[node[t].l].cnt;
            t = node[t].r;
        }
        return s + query(std::move(t1), std::move(t2), m, r, k);
    }
}

int qry(std::vector<int> &&t1, std::vector<int> &&t2, int l, int r, int k) {
    if (r - l == 1) {
        return l;
    }
    int m = (l + r) / 2;

    int s = 0;
    for (auto &t : t1) {
        s -= node[node[t].l].cnt;
    }
    for (auto &t : t2) {
        s += node[node[t].l].cnt;
    }
    if (k <= s) {
        for (auto &t : t1) {
            t = node[t].l;
        }
        for (auto &t : t2) {
            t = node[t].l;
        }
        return qry(std::move(t1), std::move(t2), l, m, k);
    } else {
        for (auto &t : t1) {
            t = node[t].r;
        }
        for (auto &t : t2) {
            t = node[t].r;
        }
        return qry(std::move(t1), std::move(t2), m, r, k - s);
    }
}

template <typename T>
struct Fenwick {
    int n;
    std::vector<T> a;
    
    Fenwick(int n_ = 0) {
        init(n_);
    }
    
    void init(int n_) {
        n = n_;
        a.assign(n, T{});
    }
    
    void add(int x, int v, int t = 1) {
        for (int i = x + 1; i <= n; i += i & -i) {
            ::add(a[i - 1], 0, N, v, t);
        }
    }
    
    std::vector<int> sum(int x) {
        std::vector<int> ans;
        for (int i = x; i > 0; i -= i & -i) {
            ans.push_back(a[i - 1]);
        }
        return ans;
    }
    
    T rangeSum(int l, int r) {
        return sum(r) - sum(l);
    }
};

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n, m;
    std::cin >> n >> m;

    std::vector<int> a(n);
    Fenwick<int> fen(n);
    for (int i = 0; i < n; ++i) {
        std::cin >> a[i];
        fen.add(i, a[i]);
    }

    auto getRank = [&](int l, int r, int k) {
        return query(fen.sum(l), fen.sum(r), 0, N, k);
    };

    auto getVal = [&](int l, int r, int k) {
        return qry(fen.sum(l), fen.sum(r), 0, N, k);
    };

    while (m--) {
        int opt;
        std::cin >> opt;

        if (opt == 1) {
            int l, r, k;
            std::cin >> l >> r >> k;
            --l;

            std::cout << getRank(l, r, k) + 1 << "\n";
        } else if (opt == 2){
            int l, r, k;
            std::cin >> l >> r >> k;
            --l;

            std::cout << getVal(l, r, k) << "\n";
        } else if (opt == 3) {
            int p, k;
            std::cin >> p >> k;
            --p;
            fen.add(p, a[p], -1);
            a[p] = k;
            fen.add(p, a[p]);
        } else if (opt == 4){
            int l, r, k;
            std::cin >> l >> r >> k;
            --l;

            int t = getRank(l, r, k);
            if (t == 0) {
                std::cout << -2147483647 << "\n";
            } else {
                std::cout << getVal(l, r, t) << "\n";
            }

        } else {
            int l, r, k;
            std::cin >> l >> r >> k;
            --l;

            int t = getRank(l, r, k + 1);
            if (t == r - l) {
                std::cout << 2147483647 << "\n";
            } else {
                std::cout << getVal(l, r, t + 1) << "\n";
            }
        }
    }   
}

LCA

LCA

#include <bits/stdc++.h>

using i64 = long long;

template<typename T>
struct RangeMinimumQuery {
    std::vector<std::vector<T>> st;
    std::function<bool(T, T)> cmp;
    RangeMinimumQuery() {}
    RangeMinimumQuery(const std::vector<T> &a, const std::function<bool(T, T)> &cmp = std::less<T>()) {
        init(a, cmp);
    }
    void init(const std::vector<T> &a, const std::function<bool(T, T)> &_cmp = std::less<T>()) {
        cmp = _cmp;
        int n = a.size();
        int l = std::__lg(n);
        st.assign(n, std::vector<T>(l + 1));

        for (int i = 0; i < n; ++i)
            st[i][0] = a[i];

        for (int j = 1; j <= l; ++j)
            for (int i = 0; i + (1 << j) <= n; ++i)
                st[i][j] = std::min(st[i][j - 1], st[i + (1 << (j - 1))][j - 1], cmp);
    }
    T rangeMin(int l, int r) {
        int k = std::__lg(r - l);
        return std::min(st[l][k], st[r - (1 << k)][k], cmp);
    }
};

template<class T,
    class Cmp = std::less<T>>
struct RMQ {
    // const Cmp cmp = Cmp();
    std::function<bool(T, T)> cmp;
    static constexpr unsigned B = 64;
    using u64 = unsigned long long;
    int n;
    std::vector<std::vector<T>> a;
    std::vector<T> pre, suf, ini;
    std::vector<u64> stk;
    RMQ() {}
    RMQ(const std::vector<T> &v) {
        init(v);
    }
    void init(const std::vector<T> &v, auto cmp) {
        this->cmp = cmp;
        n = v.size();
        pre = suf = ini = v;
        stk.resize(n);
        if (!n) {
            return;
        }
        const int M = (n - 1) / B + 1;
        const int lg = std::__lg(M);
        a.assign(lg + 1, std::vector<T>(M));
        for (int i = 0; i < M; i++) {
            a[0][i] = v[i * B];
            for (int j = 1; j < B && i * B + j < n; j++) {
                a[0][i] = std::min(a[0][i], v[i * B + j], cmp);
            }
        }
        for (int i = 1; i < n; i++) {
            if (i % B) {
                pre[i] = std::min(pre[i], pre[i - 1], cmp);
            }
        }
        for (int i = n - 2; i >= 0; i--) {
            if (i % B != B - 1) {
                suf[i] = std::min(suf[i], suf[i + 1], cmp);
            }
        }
        for (int j = 0; j < lg; j++) {
            for (int i = 0; i + (2 << j) <= M; i++) {
                a[j + 1][i] = std::min(a[j][i], a[j][i + (1 << j)], cmp);
            }
        }
        for (int i = 0; i < M; i++) {
            const int l = i * B;
            const int r = std::min(1U * n, l + B);
            u64 s = 0;
            for (int j = l; j < r; j++) {
                while (s && cmp(v[j], v[std::__lg(s) + l])) {
                    s ^= 1ULL << std::__lg(s);
                }
                s |= 1ULL << (j - l);
                stk[j] = s;
            }
        }
    } 
    T operator()(int l, int r) {
        if (l / B != (r - 1) / B) {
            T ans = std::min(suf[l], pre[r - 1], cmp);
            l = l / B + 1;
            r = r / B;
            if (l < r) {
                int k = std::__lg(r - l);
                ans = std::min({ans, a[k][l], a[k][r - (1 << k)]}, cmp);
            }
            return ans;
        } else {
            int x = B * (l / B);
            return ini[__builtin_ctzll(stk[r - 1] >> (l - x)) + l];
        }
    }
};


struct LowestCommonAncestor {
    std::vector<int> dep, euler;
    // RangeMinimumQuery<int> rmq;
    std::function<bool(int, int)> cmp = [&](int a, int b) -> bool {
        return dep[a] < dep[b];
    };
    RMQ<int> rmq;
    std::vector<int> seq;
    LowestCommonAncestor() {}
    LowestCommonAncestor(const std::vector<std::vector<int>> &e, int s) {
        init(e, s);
    }
    void init(const std::vector<std::vector<int>> &e, int s) {
        int n = e.size();
        euler.resize(n);
        dep.resize(n);
        int clock = 0;
        std::function<void(int, int)> dfs = [&](int u, int p) {
            euler[u] = clock++;
            seq.push_back(u);

            for (auto v : e[u]) {
                if (v == p)
                    continue;

                dep[v] = dep[u] + 1;
                dfs(v, u);
                seq.push_back(u);
                ++clock;
            }
        };
        dfs(s, -1);
        rmq.init(seq, cmp);
    }
    int lca(int u, int v) {
        if (euler[u] > euler[v])
            std::swap(u, v);

        return rmq(euler[u], euler[v] + 1);
        // return rmq.rangeMin(euler[u], euler[v] + 1);
    }
    int dist(int u, int v) {
        return dep[u] + dep[v] - 2 * dep[lca(u, v)];
    }
} t;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n, m, s;
    std::cin >> n >> m >> s;
    --s;

    std::vector<std::vector<int>> adj(n);
    for (int i = 1, u, v; i < n; ++i) {
        std::cin >> u >> v;
        --u, --v;
        adj[u].push_back(v);
        adj[v].push_back(u);
    }

    t.init(adj, s);

    for (int i = 0; i < m; ++i) {
        int u, v;
        std::cin >> u >> v;
        --u, --v;
        std::cout << t.lca(u, v) + 1 << "\n"; 
    }
}

FHQ-Treap

文艺平衡树

#include <bits/stdc++.h>

using i64 = long long;

std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count());
 
constexpr int L = 1E5 + 5;

struct Node {
    int w = rng();
    int x = -1;
    int siz = 0;
    int tag = 0;
    int l = 0, r = 0;
} node[L];

int tot = 0;
int newNode(int x) {
    node[++tot].x = x;
    node[tot].siz = 1;
    return tot;
}

void pull(int t) {
    node[t].siz = node[node[t].l].siz + node[node[t].r].siz + 1;
}

void tag(int t) {
    if (t) {
        node[t].tag ^= 1;
    }
}

void push(int t) {
    if (node[t].tag) {
        std::swap(node[t].l, node[t].r);
        tag(node[t].l);
        tag(node[t].r);
        node[t].tag = 0;
    }
}

std::pair<int, int> splitAt(int t, int p) {
    if (!t) {
        return {t, t};
    }
    push(t);
    if (p <= node[node[t].l].siz) {
        auto [l, r] = splitAt(node[t].l, p);
        node[t].l = r;
        pull(t);
        return {l, t};
    } else {
        auto [l, r] = splitAt(node[t].r, p - node[node[t].l].siz - 1);
        node[t].r = l;
        pull(t);
        return {t, r};
    }
}

int merge(int l, int r) {
    if (!l || !r) {
        return !l ? r : l;
    }
    if (node[l].w < node[r].w) {
        push(l);
        node[l].r = merge(node[l].r, r);
        pull(l);
        return l;
    } else {
        push(r);
        node[r].l = merge(l, node[r].l);
        pull(r);
        return r;
    }
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n, m;
    std::cin >> n >> m;
    
    int t = 0;
    for (int i = 1; i <= n; ++i) {
        t = merge(t, newNode(i));
    }
    
    auto dfs = [&](auto &&self, int u) -> void {
        if (u == 0) {
            return;
        }
        push(u);
        self(self, node[u].l);
        std::cout << node[u].x << " ";
        self(self, node[u].r);
    };
    
    for (int i = 0; i < m; ++i) {
        int l, r;
        std::cin >> l >> r;
        
        auto [u, v] = splitAt(t, r);
        auto [p, q] = splitAt(u, l - 1);
        tag(q);

        t = merge(merge(p, q), v);
    }
    
    dfs(dfs, t);
}

可持久化 Trie

来源

带着HLD 是因为懒,不想写lca

#include <bits/stdc++.h>

using i64 = long long;

constexpr int L = 6500005;

struct Node {
    int ch[2] {};
    int cnt = 0;
} pool[L];

int tot = 0;
int newNode(int t = 0) {
    pool[++tot] = pool[t];
    return tot;
}

int insert(int t, int x) {
    int root = newNode(t);
    int p = root;
    ++pool[p].cnt;
    for (int i = 30; i >= 0; --i) {
        int b = x >> i & 1;
        pool[p].ch[b] = newNode(pool[p].ch[b]);
        p = pool[p].ch[b];
        ++pool[p].cnt;
    }
    return root;
}

int query(int t1, int t2, int x) {
    int res = 0;
    for (int i = 30; i >= 0; --i) {
        int u = ~x >> i & 1;
        int cnt = pool[pool[t1].ch[u]].cnt - pool[pool[t2].ch[u]].cnt;
        if (cnt > 0) {
            res |= 1 << i;
        } else {
            u = !u;
        }
        t1 = pool[t1].ch[u];
        t2 = pool[t2].ch[u];
    }
    return res;
}

int query(int a, int b, int c, int d, int x) {
    int res = 0;
    for (int i = 30; i >= 0; --i) {
        int u = ~x >> i & 1;
        int cnt = pool[pool[a].ch[u]].cnt + pool[pool[b].ch[u]].cnt
                - pool[pool[c].ch[u]].cnt - pool[pool[d].ch[u]].cnt;
        if (cnt > 0) {
            res |= 1 << i;
        } else {
            u = !u;
        }
        a = pool[a].ch[u];
        b = pool[b].ch[u];
        c = pool[c].ch[u];
        d = pool[d].ch[u];
    }
    return res;
}

struct HLD {
    int n;
    std::vector<int> siz, top, dep, parent, in, out, seq;
    std::vector<std::vector<int>> adj;
    int cur;
    
    HLD() {}
    HLD(int n) {
        init(n);
    }
    void init(int n) {
        this->n = n;
        siz.resize(n);
        top.resize(n);
        dep.resize(n);
        parent.resize(n);
        in.resize(n);
        out.resize(n);
        seq.resize(n);
        cur = 0;
        adj.assign(n, {});
    }
    void addEdge(int u, int v) {
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
    void work(int root = 0) {
        top[root] = root;
        dep[root] = 0;
        parent[root] = -1;
        dfs1(root);
        dfs2(root);
    }
    void dfs1(int u) {
        if (parent[u] != -1) {
            adj[u].erase(std::find(adj[u].begin(), adj[u].end(), parent[u]));
        }
        
        siz[u] = 1;
        for (auto &v : adj[u]) {
            parent[v] = u;
            dep[v] = dep[u] + 1;
            dfs1(v);
            siz[u] += siz[v];
            if (siz[v] > siz[adj[u][0]]) {
                std::swap(v, adj[u][0]);
            }

        }
    }
    void dfs2(int u) {
        in[u] = cur++;
        seq[in[u]] = u;
        for (auto v : adj[u]) {
            top[v] = v == adj[u][0] ? top[u] : v;
            dfs2(v);
        }
        out[u] = cur;
    }
    int lca(int u, int v) {
        while (top[u] != top[v]) {
            if (dep[top[u]] > dep[top[v]]) {
                u = parent[top[u]];
            } else {
                v = parent[top[v]];
            }
        }
        return dep[u] < dep[v] ? u : v;
    }
    
    int dist(int u, int v) {
        return dep[u] + dep[v] - 2 * dep[lca(u, v)];
    }
    
    int jump(int u, int k) {
        if (dep[u] < k) {
            return -1;
        }
        
        int d = dep[u] - k;
        
        while (dep[top[u]] > d) {
            u = parent[top[u]];
        }
        
        return seq[in[u] - dep[u] + d];
    }
    
    bool isAncester(int u, int v) {
        return in[u] <= in[v] && in[v] < out[u];
    }
    
    int rootedParent(int u, int v) {
        std::swap(u, v);
        if (u == v) {
            return u;
        }
        if (!isAncester(u, v)) {
            return parent[u];
        }
        auto it = std::upper_bound(adj[u].begin(), adj[u].end(), v, [&](int x, int y) {
            return in[x] < in[y];
        }) - 1;
        return *it;
    }
    
    int rootedSize(int u, int v) {
        if (u == v) {
            return n;
        }
        if (!isAncester(v, u)) {
            return siz[v];
        }
        return n - siz[rootedParent(u, v)];
    }
    
    int rootedLca(int a, int b, int c) {
        return lca(a, b) ^ lca(b, c) ^ lca(c, a);
    }
};

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n, m;
    std::cin >> n >> m;

    std::vector<int> a(n);
    for (int i = 0; i < n; ++i) {
        std::cin >> a[i];
    }

    HLD t(n);
    for (int i = 0, u, v; i < n - 1; ++i) {
        std::cin >> u >> v;
        --u, --v;
        t.addEdge(u, v);
    }

    t.work();

    auto &adj = t.adj;
    std::vector<int> pathRoot(n), pre(n + 1);
    auto dfs = [&](auto &&self, int u) -> void {
        for (auto v : adj[u]) {
            pathRoot[v] = insert(pathRoot[u], a[v]);
            self(self, v);
        }
    };
    pathRoot[0] = insert(0, a[0]);
    dfs(dfs, 0);
    for (int i = 0; i < n; ++i) {
        pre[i + 1] = insert(pre[i], a[t.seq[i]]);
    }
    
    while (m--) {
        int op;
        std::cin >> op;

        if (op == 1) {
            int x, z;
            std::cin >> x >> z;
            --x;
            std::cout << query(pre[t.out[x]], pre[t.in[x]], z) << "\n";
        } else {
            int x, y, z;
            std::cin >> x >> y >> z;
            --x, --y;

            int l = t.lca(x, y);
            int p = t.parent[l] == -1 ? 0 : pathRoot[t.parent[l]];
            std::cout << std::max(query(pathRoot[x], p, z), query(pathRoot[y], p, z)) << "\n";
            // std::cout << query(pathRoot[x], pathRoot[y], pathRoot[l], p, z) << "\n";
        }
    }
}

可持久化线段树

ADD

来源

#include <bits/stdc++.h>

using i64 = long long;

constexpr int L = 1E5 + 5;

struct Node {
    int l = 0, r = 0;
    char c;
} node[20 * L];

int tot = 0;
int newNode(int t = 0) {
    node[++tot] = node[t];
    return tot;
}

int add(int t, int l, int r, int x, char v) {
    t = newNode(t);
    if (r - l == 1) {
        node[t].c = v;
        return t;
    }
    int m = (l + r) / 2;
    if (x < m) {
        node[t].l = add(node[t].l, l, m, x, v);
    } else {
        node[t].r = add(node[t].r, m, r, x, v);
    }
    return t;
}

char query(int t, int l, int r, int x) {
    if (r - l == 1) {
        return node[t].c;
    }
    int m = (l + r) / 2;
    if (x < m) {
        return query(node[t].l, l, m, x);
    }
    return query(node[t].r, m, r, x);
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n;
    std::cin >> n;

    std::vector<int> roots(1);
    std::vector<int> cnt(1);

    for (int i = 0; i < n; ++i) {
        char op;
        std::cin >> op;
        
        if (op == 'T') {
            char x;
            std::cin >> x;
            int t = add(roots.back(), 0, n, cnt.back(), x);
            roots.push_back(t);
            cnt.push_back(cnt.back() + 1);
        } else if (op == 'U') {
            int x;
            std::cin >> x;
            roots.push_back(roots[roots.size() - x - 1]);
            cnt.push_back(cnt[cnt.size() - x - 1]);
        } else {
            int x;
            std::cin >> x;
            --x;
            std::cout << query(roots.back(), 0, n, x) << "\n";
        }
    }
}

其一

来源

#include <bits/stdc++.h>

using i64 = long long;

constexpr int L = 2E7 + 4;

struct Node {
    Node *ch[2] {};
    i64 s = 0;
} pool[L];

int tot = 0;

Node *newNode(Node *t) {
    if (t) {
        pool[tot] = *t;
    }
    return &pool[tot++];
}

Node *add(Node *t, int l, int r, int x) {
    t = newNode(t);
    t->s += x;
    if (r - l == 1) {
        return t;
    }
    int m = (r + l) / 2;
    if (x < m) {
        t->ch[0] = add(t->ch[0], l, m, x);
    } else {
        t->ch[1] = add(t->ch[1], m, r, x);
    }
    return t;
}

int query(Node *t1, Node *t2, int l, int r, int x, int y) {
    if (y <= l || r <= x) {
        return 0;
    }
    if (x <= l && r <= y) {
        return (t2 ? t2->s : 0) - (t1 ? t1->s : 0);
    }
    int m = (l + r) / 2;
    return query(t1 ? t1->ch[0] : nullptr, t2 ? t2->ch[0] : nullptr, l, m, x, y) + query(t1 ? t1->ch[1] : nullptr, t2 ? t2->ch[1] : nullptr, m, r, x, y);
}

constexpr int N = 1E9 + 4;

bool chmax(auto &x, int y) {
    if (x >= y) {
        return false;
    }
    x = y;
    return true;
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n;
    std::cin >> n;

    std::vector<int> a(n);
    std::vector<Node *> rt(n + 1);
    for (int i = 0; i < n; ++i) {
        std::cin >> a[i];
        rt[i + 1] = add(rt[i], 0, N, a[i]);
    }

    int m;
    std::cin >> m;

    auto get = [&](int l, int r) -> int {
        int ans = 1;
        while (chmax(ans, query(rt[l], rt[r], 0, N, 0, ans + 1) + 1)) 
            ;
        return ans;
    };

    for (int i = 0; i < m; ++i) {
        int l, r;
        std::cin >> l >> r;
        --l;

        std::cout << get(l, r) << "\n";
    }
}
#include <bits/stdc++.h>

using i64 = long long;

constexpr int L = 2E7 + 4;

struct Node {
    int ch[2] {};
    i64 s = 0;
} node[L];

int tot = 0;

int newNode(int t) {
    node[++tot] = node[t];
    return tot;
}

int add(int t, int l, int r, int x) {
    t = newNode(t);
    node[t].s += x;
    if (r - l == 1) {
        return t;
    }
    int m = (r + l) / 2;
    if (x < m) {
        node[t].ch[0] = add(node[t].ch[0], l, m, x);
    } else {
        node[t].ch[1] = add(node[t].ch[1], m, r, x);
    }
    return t;
}

int query(int t1, int t2, int l, int r, int x, int y) {
    if (y <= l || r <= x) {
        return 0;
    }
    if (x <= l && r <= y) {
        return node[t2].s - node[t1].s;
    }
    int m = (l + r) / 2;
    return query(node[t1].ch[0], node[t2].ch[0], l, m, x, y) + query(node[t1].ch[1], node[t2].ch[1], m, r, x, y);
}

constexpr int N = 1E9 + 4;

bool chmax(auto &x, int y) {
    if (x >= y) {
        return false;
    }
    x = y;
    return true;
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n;
    std::cin >> n;

    std::vector<int> a(n);
    std::vector<int> rt(n + 1);
    for (int i = 0; i < n; ++i) {
        std::cin >> a[i];
        rt[i + 1] = add(rt[i], 0, N, a[i]);
    }

    int m;
    std::cin >> m;

    auto get = [&](int l, int r) -> int {
        int ans = 1;
        while (chmax(ans, query(rt[l], rt[r], 0, N, 0, ans + 1) + 1)) 
            ;
        return ans;
    };

    for (int i = 0; i < m; ++i) {
        int l, r;
        std::cin >> l >> r;
        --l;

        std::cout << get(l, r) << "\n";
    }
}

其二

来源

#include <bits/stdc++.h>

using i64 = long long;

constexpr int L = 3E7;

int tot;

struct Node {
    Node *l = nullptr;
    Node *r = nullptr;
    int x;
} pool[L];

Node *newNode(int x = 0) {
    pool[tot].x = x;
    return &pool[tot++];
}

Node *newNode(Node *p) {
    if (p) {
        pool[tot] = *p;
    }
    return &pool[tot++];
}

Node *build(std::vector<int> &a) {
    int n = a.size();
    return [&](this auto &&self, int l, int r) -> Node * {
        if (r - l == 1) {
            return newNode(a[l]);
        }
        int m = (l + r) / 2;
        auto u = newNode();
        *u = {self(l, m), self(m, r), 0};
        return u;
    } (0, n);
}

Node *modify(Node *t, int l, int r, int p, int c) {
    if (r - l == 1) {
        return newNode(c);
    }
    t = newNode(t);
    int m = (l + r) / 2;
    if (p < m) {
        t->l = modify(t->l, l, m, p, c);
    } else {
        t->r = modify(t->r, m, r, p, c);
    }
    return t;
}

int query(Node *t, int l, int r, int x) {
    if (r - l == 1) {
        return t->x;
    }
    int m = (l + r) / 2;
    if (x < m) {
        return query(t->l, l, m, x);
    }
    return query(t->r, m, r, x);
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n, m;
    std::cin >> n >> m;

    std::vector<int> a(n);
    for (int i = 0; i < n; ++i) {
        std::cin >> a[i];
    }

    tot = 0;

    std::vector<Node *> roots(m + 1);
    roots[0] = build(a);

    for (int i = 0; i < m; ++i) {
        int v, op, p;
        std::cin >> v >> op >> p;
        --p;

        if (op == 1) {
            int c;
            std::cin >> c;
            roots[i + 1] = modify(roots[v], 0, n, p, c);
        } else {
            roots[i + 1] = roots[v];
            std::cout << query(roots[i + 1], 0, n, p) << "\n";
        }
    }
}

动态开点 线段树

ADD

来源

#include <bits/stdc++.h>

using i64 = long long;

constexpr int L = 1E7 + 5;

struct Node {
    int l = 0, r = 0;
    int v = 0;
} node[L];

int tot = 0;
int newNode(int t = 0) {
    node[++tot] = node[t];
    return tot;
}

void pull(int p) {
    node[p].v = node[node[p].l].v + node[node[p].r].v;
}

void modify(int &t, int l, int r, int x, int v) {
    if (!t) {
        t = newNode();
    }
    if (r - l == 1) {
        node[t].v = v;
        return;
    }
    int m = (l + r) / 2;
    if (x < m) {
        modify(node[t].l, l, m, x, v);
    } else {
        modify(node[t].r, m, r, x, v);
    }
    pull(t);
}

int query(int t, int l, int r, int x, int y) {
    if (!t) {
        return 0;
    }
    if (y <= l || r <= x) {
        return 0;
    }
    if (x <= l && r <= y) {
        return node[t].v;
    }
    int m = (l + r) / 2;
    return query(node[t].l, l, m, x, y) + query(node[t].r, m, r, x, y);
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n, m;
    std::cin >> n >> m;
    
    std::vector<int> a(n);
    for (int i = 0; i < n; ++i) {
        std::cin >> a[i];
    }

    auto ord = a;
    std::sort(ord.begin(), ord.end());
    ord.erase(std::unique(ord.begin(), ord.end()), ord.end());
    auto get = [&](int x) -> int {
        return std::lower_bound(ord.begin(), ord.end(), x) - ord.begin();
    };

    int N = ord.size();

    std::vector<int> roots(N);

    for (int i = 0; i < n; ++i) {
        modify(roots[get(a[i])], 0, n, i, 1);
    }

    while (m--) {
        int o;
        std::cin >> o;

        if (o == 1) {
            int l, r, x;
            std::cin >> l >> r >> x;
            --l;
            if (x > ord.back() || x != ord[get(x)]) {
                std::cout << 0 << "\n";
                continue;
            }
            std::cout << query(roots[get(x)], 0, n, l, r) << "\n";
        } else {
            int x;
            std::cin >> x;
            --x;

            modify(roots[get(a[x])], 0, n, x, 0);
            modify(roots[get(a[x + 1])], 0, n, x + 1, 0);
            std::swap(a[x], a[x + 1]);
            modify(roots[get(a[x])], 0, n, x, 1);
            modify(roots[get(a[x + 1])], 0, n, x + 1, 1);
        }
    }
}

P13825

#include <bits/stdc++.h>

using u64 = unsigned long long;

struct Info {
    Info *l = nullptr;
    Info *r = nullptr;
    u64 tag = 0;
    u64 sum = 0;
    int act = 0;
};

void tag(Info *p, int k) {
    p->tag += k;
    p->sum += 1ULL * p->act * k;
}

void push(Info *p) {
    if (!p->l) {
        p->l = new Info{nullptr, nullptr, 0, 0, p->act / 2};
    }
    if (!p->r) {
        p->r = new Info{nullptr, nullptr, 0, 0, p->act - p->act / 2};
    }
    tag(p->l, p->tag);
    tag(p->r, p->tag);
    p->tag = 0;
}

void modify(Info *p, int l, int r, int x, int y, int k) {
    if (y <= l || r <= x) {
        return;
    }
    if (x <= l && r <= y) {
        tag(p, k);
        return;
    }
    int m = (l + r) / 2;
    push(p);
    modify(p->l, l, m, x, y, k);
    modify(p->r, m, r, x, y, k);
    p->sum += 1ULL * (std::min(r, y) - std::max(l, x)) * k;
}

u64 query(Info *p, int l, int r, int x, int y) {
    if (y <= l || r <= x) {
        return 0;
    }
    if (x <= l && r <= y) {
        return p->sum;
    }
    int m = (l + r) / 2;
    push(p);
    return query(p->l, l, m, x, y) + query(p->r, m, r, x ,y);
}


int main() {
    int n, q;
    std::cin >> n >> q;

    Info *rt = new Info{nullptr, nullptr, 0, 0, n};

    for (int op, l, r; q; --q) {
        std::cin >> op >> l >> r;
        --l;

        if (op == 1) {
            int k;
            std::cin >> k;
            modify(rt, 0, n, l, r, k);
        } else {
            std::cout << query(rt, 0, n, l, r) + 1ULL * (r - l) * (l + r + 1) / 2 << "\n";
        }
    }
}

DSU 解决单调栈

// 2023-01-03 18:00:55
// https://codeforces.com/contest/1779/submission/187755837
#include <bits/stdc++.h>

using i64 = long long;
struct DSU {
    std::vector<int> f, siz;
    DSU(int n) : f(n), siz(n, 1) { std::iota(f.begin(), f.end(), 0); }
    int leader(int x) {
        while (x != f[x]) x = f[x] = f[f[x]];
        return x;
    }
    bool same(int x, int y) { return leader(x) == leader(y); }
    bool merge(int x, int y) {
        x = leader(x);
        y = leader(y);
        if (x == y) return false;
        siz[x] += siz[y];
        f[y] = x;
        return true;
    }
    int size(int x) { return siz[leader(x)]; }
};

void solve() {
    int n;
    std::cin >> n;
    
    std::vector<int> a(n), b(n);
    for (int i = 0; i < n; i++) {
        std::cin >> a[i];
    }
    for (int i = 0; i < n; i++) {
        std::cin >> b[i];
    }
    
    int m;
    std::cin >> m;
    
    std::map<int, int> cnt;
    for (int i = 0; i < m; i++) {
        int x;
        std::cin >> x;
        cnt[x]++;
    }
    
    for (int i = 0; i < n; i++) {
        if (a[i] < b[i]) {
            std::cout << "NO\n";
            return;
        }
    }
    
    std::vector<int> p(n);
    std::iota(p.begin(), p.end(), 0);
    std::sort(p.begin(), p.end(), [&](int i, int j) {
       return b[i] < b[j];
    });
    
    DSU dsu(n);
    std::vector<int> mx(n);
    for (int i = 0; i < n; i++) {
        mx[i] = a[i] == b[i] ? -1 : b[i];
    }
    
    std::map<int, int> need;
    for (int i = 0; i < n; i++) {
        need[mx[i]]++;
    }
    auto merge = [&](int x, int y, int v) {
        if (x < 0 || x >= n) return;
        x = dsu.leader(x);
        y = dsu.leader(y);
        if (b[x] > v || b[y] > v) return;
        
        if (x == y) return;
        
        need[mx[x]]--;
        need[mx[y]]--;
        dsu.merge(x, y);
        mx[x] = std::max(mx[x], mx[y]);
        need[mx[x]]++;
    };
    
    for (int i = 0, j = 0; i < n; i = j) {
        while (j < n && b[p[i]] == b[p[j]]) j++;
        
        for (int k = i; k < j; k++) {
            merge(p[k] - 1, p[k], b[p[i]]);
            merge(p[k] + 1, p[k], b[p[i]]);
        }
        
        if (cnt[b[p[i]]] < need[b[p[i]]]) {
            std::cout << "NO\n";
            return;
        }
    }
    
    std::cout << "YES\n";
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int t;
    std::cin >> t;
    
    while (t--) {
        solve();
    }
    
    return 0;
}

stk

另一道类似的题目,单调栈

// 
// https://codeforces.com/contest/1904/submission/247175767

#include <bits/stdc++.h>

using i64 = long long;

void solve() {
    int n;
    std::cin >> n;
    
    std::vector<int> a(n), b(n);
    for (int i = 0; i < n; i++) {
        std::cin >> a[i];
    }
    for (int i = 0; i < n; i++) {
        std::cin >> b[i];
    }
    for (int i = 0; i < n; i++) {
        if (a[i] > b[i]) {
            std::cout << "NO\n";
            return;
        }
    }
    std::vector<int> l(n), r(n);
    std::vector<int> stk;
    for (int i = 0; i < n; i++) {
        while (!stk.empty() && a[stk.back()] <= a[i]) {
            stk.pop_back();
        }
        l[i] = stk.empty() ? -1 : stk.back();
        stk.push_back(i);
    }
    stk = {};
    for (int i = n - 1; i >= 0; i--) {
        while (!stk.empty() && a[stk.back()] <= a[i]) {
            stk.pop_back();
        }
        r[i] = stk.empty() ? n : stk.back();
        stk.push_back(i);
    }
    
    int j = 0;
    for (int i = 0; i < n; i++) {
        while (j < n && b[j] == a[i] && j > l[i] && j < r[i]) {
            j++;
        }
    }
    if (j == n) {
        std::cout << "YES\n";
    } else {
        std::cout << "NO\n";
    }
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int t;
    std::cin >> t;
    
    while (t--) {
        solve();
    }
    
    return 0;
}

XOR问题不用Trie

// 2022-12-13 20:14:06
// https://atcoder.jp/contests/abc281/submissions/37252293

// 2020-11-15 17:56:14
// https://codeforces.com/contest/1446/submission/98455040

#include <bits/stdc++.h>

using i64 = long long;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int N;
    std::cin >> N;
    
    std::vector<int> a(N);
    for (int i = 0; i < N; i++) {
        std::cin >> a[i];
    }
    
    std::sort(a.begin(), a.end());
    
    auto solve = [&](auto solve, int l, int r, int k) {
        if (k == 0) return 0;
        int m = std::partition_point(a.begin() + l, a.begin() + r, [&](int x) { return ~x >> (k - 1) & 1; }) - a.begin();
        if (l == m || m == r) return solve(solve, l, r, k - 1);
        return std::min(solve(solve, l, m, k - 1), solve(solve, m, r, k - 1)) | 1 << (k - 1);
    };
    
    std::cout << solve(solve, 0, N, 30) << "\n";
    
    return 0;
}
// 使用Trie
#include <bits/stdc++.h>

using i64 = long long;

constexpr int N = 1E7;

int tot;
int trie[N][2];

int newNode() {
    ++tot;
    trie[tot][0] = trie[tot][1] = 0;
    return tot;
}

void insert(int x) {
    int p = 1;
    for (int i = 30; i >= 0; --i) {
        int u = x >> i & 1;
        if (!trie[p][u]) {
            trie[p][u] = newNode();
        }
        p = trie[p][u];
    }
}


int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n;
    std::cin >> n;

    std::vector<int> a(n);
    for (int i = 0; i < n; ++i) {
        std::cin >> a[i];
    }

    tot = 0;
    newNode();

    for (int x : a) {
        insert(x);
    }

    auto dfs = [&](this auto &&self, int p, int k) -> int {
        if (p == 0) {
            return 0;
        }
        if (trie[p][0] && trie[p][1]) {
            return std::min(self(trie[p][0], k - 1), self(trie[p][1], k - 1)) | 1 << k;
        }
        return self(std::max(trie[p][0], trie[p][1]), k - 1);
    };
    
    std::cout << dfs(1, 30);
}

Trie

// 2024-06-04 15:16:29
// https://codeforces.com/contest/1980/submission/263960334

// 2024-03-05 15:26:24
// https://codeforces.com/contest/1902/submission/235588474
constexpr int N = 1E7;
 
int trie[N][2];
int cnt[N][2];
 
int tot = 0;
int newNode() {
    int x = ++tot;
    trie[x][0] = trie[x][1] = 0;
    cnt[x][0] = cnt[x][1] = 0;
    return x;
}
 
void add(int x, int d, int t = 1) {
    int p = 1;
    cnt[p][d] += t;
    for (int i = 29; i >= 0; i--) {
        int u = x >> i & 1;
        if (!trie[p][u]) {
            trie[p][u] = newNode();
        }
        p = trie[p][u];
        cnt[p][d] += t;
    }
}
 
int query(int x, int d) {
    int p = 1;
    if (!cnt[p][d]) {
        return 0;
    }
    int ans = 0;
    for (int i = 29; i >= 0; i--) {
        int u = x >> i & 1;
        if (cnt[trie[p][u ^ 1]][d]) {
            ans |= 1 << i;
            p = trie[p][u ^ 1];
        } else {
            p = trie[p][u];
        }
    }
    return ans;
}

带权DSU

#include <bits/stdc++.h>

using i64 = long long;

struct DSU {
    std::vector<int> f, siz;
    std::vector<i64> g;
    
    DSU() {}
    DSU(int n) {
        init(n);
    }
    
    void init(int n) {
        f.resize(n);
        g.resize(n);
        std::iota(f.begin(), f.end(), 0);
        siz.assign(n, 1);
    }
    
    int find(int x) {
        if (f[x] == f[f[x]]) {
            return f[x];
        }
        int y = find(f[x]);
        g[x] += g[f[x]];
        f[x] = y;
        return f[x];
    }
    
    bool same(int x, int y) {
        return find(x) == find(y);
    }
    
    bool merge(int x, int y, int w) {
        int fx = find(x);
        int fy = find(y);
        if (fx == fy) {
            return g[x] - g[y] - w == 0;
        }
        siz[fx] += siz[fy];
        g[fy] = g[x] - g[y] - w;
        f[fy] = fx;
        return true;
    }
    
    int size(int x) {
        return siz[find(x)];
    }
};

void solve() {
    int n, m;
    std::cin >> n >> m;

    std::vector<std::array<int, 3>> a(m);
    for (auto &[u, v, w] : a) {
        std::cin >> u >> v >> w;
        --u, --v;
    }

    DSU dsu(n);
    
    for (auto [u, v, w] : a) {
        if (!dsu.merge(u, v, w)) {
            std::cout << "NO\n";
            return;
        }
    }
    std::cout << "YES\n";
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int t;
    std::cin >> t;
    
    while (t--) {
        solve();
    }
}

笛卡尔树

l 和 r 的lca 为区间RMQ

// https://codeforces.com/contest/1748/submission/181116336
std::vector<int> lc(n, -1), rc(n, -1), s;
for (int i = 0; i < n; i++) {
    while (!s.empty() && a[i] < a[s.back()]) {
        int x = s.back();
        rc[x] = lc[i];
        lc[i] = x;
        s.pop_back();
    }
    s.push_back(i);
}

while (s.size() > 1) {
    int x = s.back();
    s.pop_back();
    rc[s.back()] = x;
}
std::vector<int> stk;
std::vector<int> lc(n, -1), rc(n, -1);
for (int i = 0; i < n; ++i) {
    int last = -1;
    while (!stk.empty() && a[stk.back()] > a[i]) {
        last = stk.back();
        stk.pop_back();
    }
    lc[i] = last;
    if (stk.size()) {
        rc[stk.back()] = i;
    }
    stk.push_back(i);
}

树状数组

#include <bits/stdc++.h>

using i64 = long long;

constexpr int N = 2E5 + 5;

std::vector<int> fen1(N), fen2(N);

int fenl[N], fenr[N];

void add(int *fen, int x, int y) {
    for (int i = x + 1; i < N; i += i & -i) {
        fen[i - 1] += y;
    }
}

int sum(int *fen, int x) {
    int res = 0;
    for (int i = x; i; i = i & (i - 1)) {
        res += fen[i - 1];
    }
    return res;
}

int rangeSum(int *fen, int l, int r) {
    return sum(fen, r) - sum(fen, l);
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n;
    std::cin >> n;

    std::vector<int> a(n);
    for (int i = 0; i < n; ++i) {
        std::cin >> a[i];
    }

    for (auto &x : a) {
        add(fenr, x, 1);
    }

    i64 ans0 = 0, ans1 = 0;
    for (auto &x : a) {
        ans0 += 1LL * rangeSum(fenl, x + 1, N) * rangeSum(fenr, x + 1, N);
        ans1 += 1LL * sum(fenl, x) * sum(fenr, x);
        add(fenl, x, 1);
        add(fenr, x, -1);
    }

    std::cout << ans0 << " " << ans1 << '\n';
}

线段树

#include <bits/stdc++.h>

using i64 = long long;

constexpr int L = 4E5 + 5;

struct Info {
    i64 sum = 0;
    i64 act = 1;

    i64 tag = 0;
    void apply(i64 add) {
        sum += add * act;
        tag += add;
    }
} info[L];

Info operator+(Info a, Info b) {
    Info c;
    c.sum = a.sum + b.sum;
    c.act = a.act + b.act;
    return c;
}

void pull(int p) {
    info[p] = info[2 * p] + info[2 * p + 1];
}

void push(int p) {
    info[2 * p].apply(info[p].tag);
    info[2 * p + 1].apply(info[p].tag);
    info[p].tag = 0;
}

void rangeApply(int p, int l, int r, int x, int y, i64 t) {
    if (y <= l || r <= x) {
        return;
    }
    if (x <= l && r <= y) {
        info[p].apply(t);
        return;
    }
    int m = (l + r) / 2;
    push(p);
    rangeApply(2 * p, l, m, x, y, t);
    rangeApply(2 * p + 1, m, r, x, y, t);
    pull(p);
}

Info rangeQuery(int p, int l, int r, int x, int y) {
    if (y <= l || r <= x) {
        return Info();
    }
    if (x <= l && r <= y) {
        return info[p];
    }
    push(p);
    int m = (l + r) / 2;
    return rangeQuery(2 * p, l, m, x, y) + rangeQuery(2 * p + 1, m, r, x, y);
}

void out(int p, int l, int r) {
    if (r - l == 1) {
        std::cout << info[p].sum << " ";
        return;
    }
    push(p);
    int m = (l + r) / 2;
    out(2 * p, l, m);
    out(2 * p + 1, m, r);
}


int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n, m;
    std::cin >> n >> m;

    std::vector<Info> a(n);
    for (int i = 0; i < n; ++i) {
        std::cin >> a[i].sum;
    }

    // build
    [&](this auto &&self, int p, int l, int r) -> void {
        if (r - l == 1) {
            info[p] = a[l];
            return;
        }
        int m = (l + r) / 2;
        self(2 * p, l, m);
        self(2 * p + 1, m, r);
        pull(p);
    } (1, 0, n);

    for (int i = 0; i < m; ++i) {
        int op, x, y;
        std::cin >> op >> x >> y;
        --x;
        
        if (op == 1) {
            i64 k;
            std::cin >> k;
        
            rangeApply(1, 0, n, x, y, {k});
        } else {
            std::cout << rangeQuery(1, 0, n, x, y).sum << "\n";
        }
    }

    return 0;
}

线段树二分

CF19D

#include <bits/stdc++.h>

using i64 = long long;
template<class Info,
    class Merge = std::plus<Info>>
struct SegmentTree {
    const int n;
    const Merge merge;
    std::vector<Info> info;
    SegmentTree(int n) : n(n), merge(Merge()), info(4 << std::__lg(n)) {}
    SegmentTree(std::vector<Info> init) : SegmentTree(init.size()) {
        std::function<void(int, int, int)> build = [&](int p, int l, int r) {
            if (r - l == 1) {
                info[p] = init[l];
                return;
            }
            int m = (l + r) / 2;
            build(2 * p, l, m);
            build(2 * p + 1, m, r);
            pull(p);
        };
        build(1, 0, n);
    }
    void pull(int p) {
        info[p] = merge(info[2 * p], info[2 * p + 1]);
    }
    void modify(int p, int l, int r, int x, const Info &v) {
        if (r - l == 1) {
            info[p] = v;
            return;
        }
        int m = (l + r) / 2;
        if (x < m) {
            modify(2 * p, l, m, x, v);
        } else {
            modify(2 * p + 1, m, r, x, v);
        }
        pull(p);
    }
    void modify(int p, const Info &v) {
        modify(1, 0, n, p, v);
    }
    Info rangeQuery(int p, int l, int r, int x, int y) {
        if (l >= y || r <= x) {
            return Info();
        }
        if (l >= x && r <= y) {
            return info[p];
        }
        int m = (l + r) / 2;
        return merge(rangeQuery(2 * p, l, m, x, y), rangeQuery(2 * p + 1, m, r, x, y));
    }
    Info rangeQuery(int l, int r) {
        return rangeQuery(1, 0, n, l, r);
    }
    template<class F>
    int findFirst(int p, int l, int r, int x, int y, F pred) {
        if (l >= y || r <= x || !pred(info[p])) {
            return -1;
        }
        if (r - l == 1) {
            return l;
        }
        int m = (l + r) / 2;
        int res = findFirst(2 * p, l, m, x, y, pred);
        if (res == -1) {
            res = findFirst(2 * p + 1, m, r, x, y, pred);
        }
        return res;
    }
    template<class F>
    int findFirst(int l, int r, F pred) {
        return findFirst(1, 0, n, l, r, pred);
    }
};

struct Info {
    int max = -1;
};

Info operator+(Info a, Info b) {
    return {std::max(a.max, b.max)};
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int n;
    std::cin >> n;
    
    std::vector<std::string> o(n);
    std::vector<int> x(n), y(n);
    for (int i = 0; i < n; i++) {
        std::cin >> o[i] >> x[i] >> y[i];
    }
    auto v = x;
    std::sort(v.begin(), v.end());
    std::vector<std::set<int>> s(n, {-1});
    SegmentTree<Info> seg(n);
    for (int i = 0; i < n; i++) {
        x[i] = std::lower_bound(v.begin(), v.end(), x[i]) - v.begin();
        if (o[i] == "add") {
            s[x[i]].insert(y[i]);
            seg.modify(x[i], {*s[x[i]].rbegin()});
        } else if (o[i] == "remove") {
            s[x[i]].erase(y[i]);
            seg.modify(x[i], {*s[x[i]].rbegin()});
        } else {
            int X = seg.findFirst(x[i] + 1, n, [&](auto a) {
                return a.max > y[i];
            });
            if (X == -1) {
                std::cout << -1 << "\n";
                continue;
            }
            std::cout << v[X] << " " << *s[X].upper_bound(y[i]) << "\n";
        }
    }
    
    return 0;
}

懒标记线段树

#include <bits/stdc++.h>

using i64 = long long;

constexpr int L = 4E5 + 5;

std::vector<int> len(L);
std::vector<int> cnt(L);
std::vector<int> tag(L);

void apply(int p) {
    tag[p] ^= 1;
    cnt[p] = len[p] - cnt[p];
}

void push(int p) {
    if (tag[p] == 0) {
        return;
    }
    tag[p] = 0;
    apply(2 * p);
    apply(2 * p + 1);
}

void pull(int p) {
    cnt[p] = cnt[2 * p] + cnt[2 * p + 1];
    // len[p] = len[2 * p] + len[2 * p + 1];
}

void modify(int p, int l, int r, int x, int y) {
    if (r <= x || y <= l) {
        return;
    }
    if (x <= l && r <= y) {
        apply(p);
        return;
    }
    push(p);
    int m = (l + r) / 2;
    modify(2 * p, l, m, x, y);
    modify(2 * p + 1, m, r, x, y);
    pull(p);
}

int query(int p, int l, int r, int x, int y) {
    if (r <= x || y <= l) {
        return 0;
    }
    if (x <= l && r <= y) {
        return cnt[p];
    }
    push(p);
    int m = (l + r) / 2;
    return query(2 * p, l, m, x, y) + query(2 * p + 1, m, r, x, y);
}

auto out(int p, int l, int r) -> void {
    if (r - l == 1) {
        std::cout << cnt[p] << ' ';
        return;
    }
    push(p);
    int m = (l + r) / 2;
    out(2 * p, l, m);
    out(2 * p + 1, m, r);
    if (p == 1) {
        std::cout << std::endl;
    }
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n, m;
    std::cin >> n >> m;

    // build
    [&](this auto &&self, int p, int l, int r) -> void {
        len[p] = r - l;
        if (r - l == 1) {
            return;
        }
        int m = (l + r) / 2;
        self(2 * p, l, m);
        self(2 * p + 1, m, r);
    } (1, 0, n);

    for (int i = 0; i < m; ++i) {
        int c, a, b;
        std::cin >> c >> a >> b;
        --a;

        if (c == 0) {
            modify(1, 0, n, a, b);
        } else {
            std::cout << query(1, 0, n, a, b) << "\n";
        }
    }
}
posted @ 2026-04-04 15:10  filt  阅读(7)  评论(0)    收藏  举报