数据结构模板汇总

  1. 单调栈

P5788 【模板】单调栈

#include
using namespace std;
#define LL long long 
const LL N = 3e6 + 10;
LL  a[N];
int stack[N],f[N];
int main() {
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
    }
    int cur = 1;
    f[n] = 0;
    stack[cur] = n;
    for (int i = n - 1; i > 0; --i) {
        while (cur > 0&&a[i] >= a[stack[cur]]) {
            cur--;
        }
        if (cur == 0) {
            f[i] = 0;
            stack[++cur] = i;
        }
        else {
            f[i] = stack[cur];
            stack[++cur] = i;
        }
    }
    for (int i = 1; i <= n; ++i) cout << f[i] << " ";
    return 0;
}
  1. 单调队列

P1886 滑动窗口 /【模板】单调队列

#include
using namespace std;
const LL N = 1e6 + 10;
int a[N],que[N];
int main() {
    int n, k;
    cin >> n >> k;
    for (int i = 1; i <= n; ++i) cin >> a[i];
    int front = 1, rear = 0;
    for (int i = 1; i <= n; ++i) {
        while (front <= rear && a[que[rear]] >= a[i]) rear--;
        que[++rear] = i;
        while (que[front] <= i - k) front++;
        if (i >= k) cout << a[que[front]] << " ";
    }
    cout << '\n';
    front = 1, rear = 0;
    for (int i = 1; i <= n; ++i) {
        while (front <= rear && a[que[rear]] <= a[i]) rear--;
        que[++rear] = i;
        while (que[front] <= i - k) front++;
        if (i >= k) cout << a[que[front]] << " ";
    }
    return 0;
}
  1. ST表

P3865 【模板】ST 表

预处理

查询

#include
#include
using namespace std;
#define LL long long 
const LL N = 1e5 + 10;
int n, m, a[N],f[N][20];
void prework() {
    for (int i = 1; i <= n; ++i) f[i][0] = a[i];
    int k = log2(n);
    for (int i = 1; i <= k; ++i) {
        for (int j = 1; j + (1 << i) - 1 <= n; ++j) {
            f[j][i] = max(f[j][i - 1], f[j + (1 << (i - 1))][i - 1]);
        }
    }
}
void enquire(int l,int r) {
    int k = log2(r - l + 1);
    cout <> n >> m;
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
    }
    prework();
    for (int i = 0; i < m; ++i) {
        int l, r;
        cin >> l >> r;
        enquire(l, r);
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin >> _t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 并查集

P3367 【模板】并查集

#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define LL long long 
const LL N = 1e5 + 10;
int f[N],cnt[N];
int n, m;
void init() {
    for (int i = 1; i <= n; ++i) f[i] = i;
}
int find(int x) {
    if (x == f[x]) return x;
    return f[x] = find(f[x]);
}
void merge(int a, int b) {
    a = find(a);
    b = find(b);
    if (a == b) return;
    if (cnt[a] >cnt[b]) {
        f[b] = a;
    }
    else {
        if (cnt[a] == cnt[b]) cnt[b]++;
        f[a] = b;
    }
}
bool query(int x, int y) {
    return find(x) == find(y);
}
void solve() {
    cin >> n >> m;
    init();
    for (int i = 1; i <= m; ++i) {
        int op, x, y;
        cin >> op >> x >> y;
        if (op == 1) merge(x, y);
        else {
            if (query(x, y)) cout << "Y\n";
            else cout << "N\n";
        }
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 拓展域并查集

P1525 [NOIP2010 提高组] 关押罪犯

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define LL long long 
const LL N = 2e4 + 10;
const LL M = 1e5 + 10;
int fa[N*2],cnt[N*2];
int n, m;
struct node {
    int a, b, c;
    bool operator<(const node x)const {
        return c > x.c;
    }
}th[M];
void init() {
    for (int i = 1; i <= 2 * n; ++i) {
        fa[i] = i;
        cnt[i] = 1;
    }
}
int find(int a) {
    if (a == fa[a]) return a;
     return fa[a] = find(fa[a]);

}
void merge(int a, int b) {
    a = find(a);
    b = find(b);
    if (a == b) return;
    if (cnt[a] >cnt[b]) {
        fa[b] = a;
    }
    else {
        if (cnt[a] == cnt[b]) cnt[b]++;
        fa[a] = b;
    }
}
bool query(int a, int b) {
    return find(a) == find(b);
}
void solve() {
    cin >> n >> m;
    init();
    for (int i = 0; i < m; ++i) {
        cin >> th[i].a >> th[i].b >> th[i].c;
    }
    sort(th, th + m);
    for (int i = 0; i < m; ++i) {
        if (query(th[i].a, th[i].b )||query(th[i].a+n,th[i].b+n)) {
            cout<> _t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 带权并查集

P2024 [NOI2001] 食物链

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define LL long long 
const LL N = 5e4 + 10;
const LL M = 1e5 + 10;
int fa[N], cnt[N],va[N];
int n, m,ans=0;
struct node {
    int a, b, c;
    bool operator<(const node x)const {
        return c > x.c;
    }
}th[M];
void init() {
    for (int i = 1; i <=  n; ++i) {
        fa[i] = i;
        cnt[i] = 1;
        va[i] = 0;
    }
}
int find(int a) {
    if (a == fa[a]) return a;
    int temp = find(fa[a]);
    va[a] = (va[a] + va[fa[a]]) % 3;
    fa[a] = temp;
    return fa[a];
}
void merge(int a, int b,int op) {
    int aa = find(a), bb = find(b);
    if (aa == bb) return;
    if (cnt[aa] > cnt[bb]) {
        fa[bb] = aa;
        va[bb] = (va[a] - va[b] -op+ 3) % 3;
    }
    else {
        if (cnt[aa] == cnt[bb]) cnt[bb]++;
        fa[aa] = bb;
        va[aa] = (va[b] - va[a] +op+ 3) % 3;
    }
}
int query(int a, int b) {
    int aa = find(a), bb = find(b);
    if (aa != bb) return -1;
    else return (va[a] - va[b] + 3) % 3;
}
void solve() {
    cin >> n >> m;
    init();
    for (int i = 0; i < m; ++i) {
        int op, a, b;
        cin >> op >> a >> b;
        op--;
        if (a > n || b > n || op == 1 && a == b||query(a,b)!=op&&query(a,b)!=-1) ans++;
        else merge(a, b, op);
    }
    cout << ans;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin >> _t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 可持久化并查集

P3402 可持久化并查集

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
#define P pair
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 2e5 + 10;
struct tree {
    int l, r, fa, siz;
}tr[N << 5];
int n, m, cur;
int cnt, root[N];
int build(int l, int r) {
    int x = ++cnt;
    if (l == r) {
        tr[x].fa = l;
        tr[x].siz = 1;
        return x;
    }
    int mid = l + r >> 1;
    tr[x].l = build(l, mid);
    tr[x].r = build(mid + 1, r);
    return x;
}
int modifyfa(int x, int l, int r, int a, int b) {
    int u = ++cnt;
    tr[u].l = tr[x].l, tr[u].r = tr[x].r;
    if (l == r) {
        tr[u].fa = b;
        tr[u].siz = tr[x].siz;
        return u;
    }
    int mid = l + r >> 1;
    if (a <= mid) tr[u].l = modifyfa(tr[x].l, l, mid, a, b);
    else tr[u].r = modifyfa(tr[x].r, mid + 1, r, a, b);
    return u;
}
int modifysiz(int x, int l, int r, int a, int b) {
    int u = ++cnt;
    tr[u].l = tr[x].l, tr[u].r = tr[x].r;
    if (l == r) {
        tr[u].siz = b;
        tr[u].fa = tr[x].fa;
        return u;
    }
    int mid = l + r >> 1;
    if (a <= mid) tr[u].l = modifysiz(tr[x].l, l, mid, a, b);
    else tr[u].r = modifysiz(tr[x].r, mid + 1, r, a, b);
    return u;
}
int queryfa(int x, int l, int r, int k) {
    if (l == r) return tr[x].fa;
    int mid = l + r >> 1;
    if (k <= mid) return queryfa(tr[x].l, l, mid, k);
    else return queryfa(tr[x].r, mid + 1, r, k);
}
int querysiz(int x, int l, int r, int k) {
    if (l == r) return tr[x].siz;
    int mid = l + r >> 1;
    if (k <= mid) return querysiz(tr[x].l, l, mid, k);
    else return querysiz(tr[x].r, mid + 1, r, k);
}
int find(int x) {
    int f = queryfa(root[cur], 1, n, x);
    if (f == x) return f;
    else return find(f);
}
void  merge(int a, int b) {
    a = find(a), b = find(b);
    if (a == b) {
        root[cur + 1] = root[cur];
        return;
    }
    int siz1 = querysiz(root[cur], 1, n, a), siz2 = querysiz(root[cur], 1, n, b);
    if (siz1 < siz2) {
        root[cur + 1] = modifyfa(root[cur], 1, n, a, b);
        root[cur + 1] = modifysiz(root[cur + 1], 1, n, b, siz1 + siz2);
    }
    else {
        root[cur + 1] = modifyfa(root[cur], 1, n, b, a);
        root[cur + 1] = modifysiz(root[cur + 1], 1, n, a, siz1 + siz2);
    }
}
void solve() {
    cin >> n >> m;
    root[0] = build(1, n);
    for (int i = 1; i <= m; ++i) {
        int op;
        cin >> op;
        if (op == 1) {
            int a, b;
            cin >> a >> b;
            merge(a, b);
        }
        else if (op == 2) {
            int k;
            cin >> k;
            root[cur + 1] = root[k];
        }
        else {
            int a, b;
            cin >> a >> b;
            cout << (find(a) == find(b)) << '\n';
            root[cur + 1] = root[cur];
        }
        cur++;
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 树状数组

P3374 【模板】树状数组 1

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define LL long long 
const LL N = 5e5 + 10;
int n, m;
int c[N];
inline int lowbit(int x) {
    return x & -x;
}
void add(int x, int y) {
    for (; x <= n; x += lowbit(x)) c[x] += y;
}
int sum(int x) {
    int res = 0;
    for (; x; x -= lowbit(x)) res += c[x];
    return res;
}
void solve() {
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) {
        int x;
        cin >> x;
        add(i, x);
    }
    for (int i = 0; i < m; ++i) {
        int op,x,y;
        cin >> op>>x>>y;
        if (op == 1) add(x, y);
        else cout << sum(y) - sum(x-1) << '\n';
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t
    while (_t--) {
        solve();
    }
    return 0;
}

P1908 逆序对

#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
const ll N = 5e5 + 10;
int n, m;
int a[N], b[N], c[N];
ll ans = 0;
inline int lowbit(int x) {
    return x & -x;
}
void add(int x, int k) {
    for (; x <= m; x += lowbit(x)) c[x] += k;
}
void  query(int x) {
    for (; x; x -= lowbit(x)) ans += c[x];
}
void solve() {
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
        b[i] = a[i];
    }
    sort(b + 1, b + n + 1);
    m = unique(b + 1, b + n + 1) - b - 1;
    for (int i = 1; i <= n; ++i) {
        a[i] = lower_bound(b + 1, b + m + 1, a[i]) - b;
    }
    for (int i = n; i > 0; --i) {
        add(a[i], 1);
        query(a[i] - 1);
    }
    cout << ans;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 线段树

P3372 【模板】线段树 1

时间

空间

#include
#include
#include
#include
#include
#include
using namespace std;
#define LL long long
const LL N = 1e5 + 10;
LL sum[4 * N], tag[4 * N], sze[4 * N], a[N];
void pushtag(int x, LL k) {
    sum[x] += sze[x] * k;
    tag[x] += k;
}
void pushdown(int x) {
    if (tag[x]) {
        pushtag(x << 1, tag[x]);
        pushtag(x << 1 | 1, tag[x]);
        tag[x] = 0;
    }
}
void pushup(int x) {
    sum[x] = sum[x << 1] + sum[x << 1 | 1];
    sze[x] = sze[x << 1] + sze[x << 1 | 1];
}
void build(int x, int l, int r) {
    if (l == r) {
        sum[x] = a[l];
        sze[x] = 1;
        return;
    }
    int mid = (l + r) >> 1;
    build(x << 1, l, mid);
    build(x << 1 | 1, mid + 1, r);
    pushup(x);
}
void add(int x, int l, int r, int ql, int qr, LL k) {
    if (ql <= l && qr >= r) {
        pushtag(x, k);
        return;
    }
    pushdown(x);
    int mid = (l + r) >> 1;
    if (ql <= mid) add(x << 1, l, mid, ql, qr, k);
    if (qr > mid) add(x << 1 | 1, mid + 1, r, ql, qr, k);
    pushup(x);
}
LL query(int x, int l, int r, int ql, int qr) {
    if (ql <= l && qr >= r) return sum[x];
    pushdown(x);
    int mid = (l + r) >> 1;
    LL ans = 0;
    if (ql<=mid) ans += query(x << 1, l, mid, ql, qr);
    if (qr > mid) ans += query(x << 1 | 1, mid + 1, r, ql, qr);
    return ans;
}
void solve() {
    int n, m;
    cin >> n>>m;
    for (int i = 1; i <= n; ++i) cin >> a[i];
    build(1, 1, n);
    for (int i = 1; i <= m; ++i) {
        int op, x, y;
        cin >> op >> x >> y;
        if (op == 1) {
            LL k;
            cin >> k;
            add(1, 1, n, x, y, k);
        }
        else cout << query(1, 1, n, x, y) << '\n';
    }

}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) solve();
    return 0;
}
  1. 线段树区间合并

hdu1540 Tunnel Warfare

参考博客

#include 
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
typedef long long ll;
const int N = 5e4 + 10;
struct node {
    int l, r;
    int lmax, rmax; //左右最大连续长度
}t[N << 2];
void pushup(node& p, node& l, node& r) { //区间合并
    p.lmax = l.lmax + (l.lmax == l.r - l.l + 1 ? r.lmax : 0);
    p.rmax = r.rmax + (r.rmax == r.r - r.l + 1 ? l.rmax : 0);
}
void pushup(int x) { pushup(t[x], t[x << 1], t[x << 1 | 1]); }
void build(int l, int r, int x = 1) {
    t[x] = { l, r, 1, 1 };
    if (l == r) return;
    int mid = l + r >> 1;
    build(l, mid, x << 1), build(mid + 1, r, x << 1 | 1);
    pushup(x);
}
void modify(int a, int c, int x = 1) {
    if (t[x].l == t[x].r) {
        t[x].lmax = t[x].rmax = c;
        return;
    }
    int mid = t[x].l + t[x].r >> 1;
    modify(a, c, x << 1 | (a > mid));
    pushup(x);
}
int ask(int a, int x = 1) {
    if (t[x].l == t[x].r) return t[x].lmax;
    int mid = t[x].l + t[x].r >> 1;
    if (a <= mid) { //表明a在左子树, 看看左子树右连续区间是否包含a点
        node& op = t[x << 1];
        if (a >= op.r - op.rmax + 1) return op.rmax + t[x << 1 | 1].lmax;
        return ask(a, x << 1); //不包含a
    }
    else { //表明a在右子树, 看看右子树左连续区间是否包含a点
        node& op = t[x << 1 | 1];
        if (a <= op.l + op.lmax - 1) return op.lmax + t[x << 1].rmax;
        return ask(a, x << 1 | 1); //不包含a
    }
}
int main(){
    int n, m;
    while (~scanf("%d %d", &n, &m)) {
        stack st; //记录最后被删除的点
        build(1, n);
        rep(i, m) {
            char s[2]; scanf("%s", s);
            if (s[0] == 'D') {
                int a; scanf("%d", &a);
                modify(a, 0);
                st.push(a);
            }
            else if (s[0] == 'Q') {
                int a; scanf("%d", &a);
                printf("%d\n", ask(a));
            }
            else modify(st.top(), 1), st.pop();
        }
    }
    return 0;
}
  1. 吉司机线段树

P6242 【模板】线段树 3

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define LL long long 
#define P pair
const double eps = 1e-8;
const LL N = 2e6 + 10;
const LL INF = 1e10;
LL n, m, a[N], sum[N], maxn[N], sze[N], se[N], maxt[N], maxh[N], tag1[N], tag2[N], tag3[N], tag4[N];
LL read() {
    LL res = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch>'9') { if (ch == '-') { f = -1; } ch = getchar(); }
    while (ch >= '0' && ch <= '9') { res = res * 10 + ch - '0', ch = getchar(); }
    return f * res;
}
void pushtag(int x, LL k1, LL k2, LL k3, LL k4) {
    sum[x] += k1 * maxt[x] + k3 * (sze[x] - maxt[x]);
    maxh[x] = max(maxh[x], maxn[x] + k2);
    tag2[x] = max(tag2[x], tag1[x] + k2);
    tag1[x] += k1;
    maxn[x] += k1;
    tag4[x] = max(tag4[x], tag3[x] + k4);
    tag3[x] += k3;
    if (se[x] != -INF) se[x] += k3;
}
void pushdown(int x) {
    LL temp = max(maxn[x << 1], maxn[x << 1 | 1]);
    if (temp == maxn[x << 1]) pushtag(x << 1, tag1[x], tag2[x], tag3[x], tag4[x]);
    else pushtag(x << 1, tag3[x], tag4[x], tag3[x], tag4[x]);
    if (temp == maxn[x << 1 | 1]) pushtag(x << 1 | 1, tag1[x], tag2[x], tag3[x], tag4[x]);
    else pushtag(x << 1 | 1, tag3[x], tag4[x], tag3[x], tag4[x]);
    tag1[x] = tag2[x] = tag3[x] = tag4[x] = 0;
}
void pushup(int x) {
    sum[x] = sum[x << 1] + sum[x << 1 | 1];
    sze[x] = sze[x << 1] + sze[x << 1 | 1];
    maxn[x] = max(maxn[x << 1], maxn[x << 1 | 1]);
    maxh[x] = max(maxh[x << 1], maxh[x << 1 | 1]);
    if (maxn[x << 1] == maxn[x << 1 | 1]) {
        maxt[x] = maxt[x << 1] + maxt[x << 1 | 1];
        se[x] = max(se[x << 1], se[x << 1 | 1]);
    }
    else {
        se[x] = max(min(maxn[x << 1], maxn[x << 1 | 1]), max(se[x << 1], se[x << 1 | 1]));
        maxt[x] = maxn[x << 1] > maxn[x << 1 | 1] ? maxt[x << 1] : maxt[x << 1 | 1];
    }
}
void build(int x, int l, int r) {
    if (l == r) {
        sum[x] = maxn[x] = maxh[x] = a[l];
        sze[x] = maxt[x] = 1;
        se[x] = -INF;
        return;
    }
    int mid = (l + r) >> 1;
    build(x << 1, l, mid);
    build(x << 1 | 1, mid + 1, r);
    pushup(x);
}
void add(int x, int l, int r, int ql, int qr, LL k) {
    if (ql <= l && qr >= r) {
        pushtag(x, k, k, k, k);
        return;
    }
    pushdown(x);
    int mid = (l + r) >> 1;
    if (ql <= mid) add(x << 1, l, mid, ql, qr, k);
    if (qr > mid)add(x << 1 | 1, mid + 1, r, ql, qr, k);
    pushup(x);
}
void modify(int x, int l, int r, int ql, int qr, LL k) {
    if (k >= maxn[x]) return;
    if (ql <= l && qr >= r && kse[x]) {
        pushtag(x, k - maxn[x], k - maxn[x], 0, 0);
        return;
    }
    pushdown(x);
    int mid = (l + r) >> 1;
    if (ql <= mid) modify(x << 1, l, mid, ql, qr, k);
    if (qr > mid) modify(x << 1 | 1, mid + 1, r, ql, qr, k);
    pushup(x);
}
LL querysum(int x, int l, int r, int ql, int qr) {
    if (ql <= l && qr >= r)  return sum[x];
    LL ans = 0;
    pushdown(x);
    int mid = (l + r) >> 1;
    if (ql <= mid) ans += querysum(x << 1, l, mid, ql, qr);
    if (qr > mid) ans += querysum(x << 1 | 1, mid + 1, r, ql, qr);
    return ans;
}
LL querymaxa(int x, int l, int r, int ql, int qr) {
    if (ql <= l && qr >= r) return maxn[x];
    LL ans = -INF;
    pushdown(x);
    int mid = (l + r) >> 1;
    if (ql <= mid) ans = max(ans, querymaxa(x << 1, l, mid, ql, qr));
    if (qr > mid) ans = max(ans, querymaxa(x << 1 | 1, mid + 1, r, ql, qr));
    return ans;
}
LL querymaxb(int x, int l, int r, int ql, int qr) {
    if (ql <= l && qr >= r) return maxh[x];
    LL ans = -INF;
    pushdown(x);
    int mid = (l + r) >> 1;
    if (ql <= mid) ans = max(ans, querymaxb(x << 1, l, mid, ql, qr));
    if (qr > mid) ans = max(ans, querymaxb(x << 1 | 1, mid + 1, r, ql, qr));
    return ans;
}
void solve() {
    n = read(), m = read();
    for (int i = 1; i <= n; ++i) a[i] = read();
    build(1, 1, n);
    for (int i = 1; i <= m; ++i) {
        int op = read(), l = read(), r = read();
        if (op == 1) {
            LL k = read();
            add(1, 1, n, l, r, k);
        }
        else if (op == 2) {
            LL k = read();
            modify(1, 1, n, l, r, k);
        }
        else if (op == 3) cout << querysum(1, 1, n, l, r) << '\n';
        else if (op == 4) cout << querymaxa(1, 1, n, l, r) << '\n';
        else cout << querymaxb(1, 1, n, l, r) << '\n';
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 李超线段树

P4097 [HEOI2013] Segment

  1. 扫描线(面积)

P5490 【模板】扫描线

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define LL long long 
#define P pair
const double eps = 1e-8;
const LL INF = 1e18;
const LL N = 1e5 + 10;
struct Line {
    LL xl, xr, y;
    int inout;
    Line(LL xl,LL xr,LL y,int inout):xl(xl),xr(xr),y(y),inout(inout){}
    Line(){}
    bool operator<(const Line a)const {
        return y < a.y;
    }
}line[2 * N];
LL xx[2 * N], len[8 * N], tag[8 * N],ans=0;
int cnt = 0, num = 0;
void pushup(int x, int l,int r) {
    if (tag[x]) len[x] = xx[r+1] - xx[l];
    else if (l == r)  len[x] = 0;
    else len[x] = len[x << 1] + len[x << 1 | 1];
}
void modify(int x, int l, int r, int ql, int qr,int inout) {
    if (l >= ql && r <= qr) {
        tag[x] += inout;
        pushup(x,l,r);
        return;
    }
    int mid = (l + r) >> 1;
    if (ql <= mid) modify(x << 1, l, mid, ql, qr, inout);
    if (qr > mid) modify(x << 1 | 1, mid+1, r, ql, qr, inout);
    pushup(x,l,r);
}
void solve() {
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        LL x1, y1, x2, y2;
        cin >> x1 >> y1 >> x2 >> y2;
        line[++cnt] = Line(x1, x2, y1, 1);
        xx[cnt] = x1;
        line[++cnt] = Line(x1, x2, y2, -1);
        xx[cnt] = x2;
    }
    sort(line + 1, line + cnt + 1);
    sort(xx + 1, xx + cnt + 1);
    num = unique(xx + 1, xx + cnt + 1) - (xx + 1);
    for (int i = 1; i <= cnt; ++i) {
        ans += len[1] * (line[i].y - line[i-1].y);
        int ql = lower_bound(xx + 1, xx + num + 1, line[i].xl) - xx;
        int qr = lower_bound(xx + 1, xx + num + 1, line[i].xr) - xx-1;
        modify(1, 1, num-1, ql, qr,line[i].inout);
    }
    cout << ans;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 扫描线(周长)

hdu1828 Picture

参考博客

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
#define mem(a,x) memset(a,x,sizeof(a))
#define ls i<<1
#define rs i<<1|1
#define m(i) ((q[i].l + q[i].r)>>1)
const int N = 5e3 + 10;
const int M = 2e4 + 10;
const int inf = 1<<29;
struct Edge//扫描线{
    int l,r;//左右端点的横坐标
    int h;//这条线的高度,即纵坐标
    int f;//标记这条边是上边(-1)还是下边(1)
}e[2*N];
bool cmp(Edge a,Edge b){
    return a.h < b.h;//高度从小到大排,扫描线自下而上扫
}
struct Node{
    int l,r;//该节点代表的线段的左右端点坐标
    int len;//这个区间被覆盖的长度
    int s;//表示这个区间被重复覆盖了几次
    bool lc,rc;//表示这个节点左右两个端点是否被覆盖(0表示没有被覆盖,1表示有被覆盖)
    int num;//这个区间有多少条线段(这个区间被多少条线段覆盖)
    //len用来计算横线 num用来计算竖线
}q[4*M];
void pushup(int i){//区间合并
    if (q[i].s){//整个区间被覆盖
        q[i].len = q[i].r - q[i].l + 1;
        q[i].lc = q[i].rc = 1;
        q[i].num = 1;
    }
    else if (q[i].l == q[i].r){//这是一个点而不是一条线段
        q[i].len = 0;
        q[i].lc = q[i].rc = 0;
        q[i].num = 0;
    }
    else{//是一条没有整个区间被覆盖的线段,合并左右子的信息
        q[i].len = q[ls].len + q[rs].len ;//长度之和
        q[i].lc = q[ls].lc;q[i].rc = q[rs].rc;//和左儿子共左端点,和右儿子共右端点
        q[i].num = q[ls].num + q[rs].num  - (q[ls].rc&q[rs].lc);
        //如果左子的右端点和右子的左端点都被覆盖了
    }
}
void build (int i,int l,int r){
    q[i].l = l,q[i].r = r;
    q[i].s = q[i].len = 0;
    q[i].lc = q[i].rc = q[i].num = 0;
    if (l == r) return;
    int mid = m(i);
    build(ls,l,mid);
    build(rs,mid+1,r);
}
void update(int i,int l,int r,int xx){
    if (l == q[i].l && q[i].r == r){
        q[i].s += xx;
        pushup(i);
        return;
    }
    int mid = m(i);
    if (r <= mid) update(ls,l,r,xx);
    else if (l > mid) update(rs,l,r,xx);
    else{
        update(ls,l,mid,xx);
        update(rs,mid+1,r,xx);
    }
    pushup(i);
}
int main(){
    int n;
    while (cin>>n){
        int x1,x2,y1,y2,mx = -inf,mn = inf;
        int tot = 0;
        for (int i = 0;i < n;++i){
            scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
            mx = max(mx,max(x1,x2));
            mn = min(mn,min(x1,x2));
            Edge & t1 = e[tot];Edge & t2 = e[tot+1];
            t1.l = t2.l = x1,t1.r = t2.r = x2;
            t1.h = y1;t1.f = 1;
            t2.h = y2;t2.f = -1;
            tot += 2;
        }
        sort(e,e+tot,cmp);
        //数据小可以不离散化
        int ans = 0;//计算周长
        int last = 0;//保存上一次的总区间的被覆盖的长度
        build(1,mn,mx-1);
        //每两条横线之间才会有竖线
        for (int i = 0;i < tot;++i){
            update(1,e[i].l,e[i].r-1,e[i].f);//根据扫描线更新
            //横线:现在这次总区间被覆盖的程度和上一次总区间被覆盖的长度之差的绝对值
            ans += abs(q[1].len - last);
            //竖线:[下一条横线的高度-现在这条横线的高度]*2*num
            ans += (e[i+1].h - e[i].h)*2*q[1].num;
            last = q[1].len;//每次都要更新上一次总区间覆盖的长度
        }
        printf("%d\n",ans);
    }
    return 0;
}
  1. 线段树套线段树

hdu1823 Luck and Love

参考博客

#include
using namespace std;
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
int n, s[1005][4005];
void subBuild(int xrt, int l, int r, int rt) {
    s[xrt][rt] = -1;
    if(l != r) {
        int m = l + r >> 1;
        subBuild(xrt, lson);
        subBuild(xrt, rson);
    }
}
void build(int l, int r, int rt) {
    subBuild(rt, 0, n, 1);
    if(l != r) {
        int m = l + r >> 1;
        build(lson);
        build(rson);
    }
}
void subUpdate(int xrt, int y, int c, int l, int r, int rt) {
    if(l == r && l == y) s[xrt][rt] = max(s[xrt][rt], c);
    else {
        int m = l + r >> 1;
        if(y <= m) subUpdate(xrt, y, c, lson);
        else subUpdate(xrt, y, c, rson);
        s[xrt][rt] = max(s[xrt][rt << 1], s[xrt][rt << 1 | 1]);
    }
}
void update(int x, int y, int c, int l, int r, int rt) {
    subUpdate(rt, y, c, 0, n, 1);
    if(l != r) {
        int m = l + r >> 1;
        if(x <= m) update(x, y, c, lson);
        else update(x, y, c, rson);
    }
}
int subQuery(int xrt, int yl, int yr, int l, int r, int rt) {
    if(yl <= l && r <= yr) return s[xrt][rt];
    else {
        int m = l + r >> 1;
        int res = -1;
        if(yl <= m) res = subQuery(xrt, yl, yr, lson);
        if(yr > m) res = max(res, subQuery(xrt, yl, yr, rson));
        return res;
    }
}
int query(int xl, int xr, int yl, int yr, int l, int r, int rt) {
    if(xl <= l && r <= xr) return subQuery(rt, yl, yr, 0, n, 1);
    else {
        int m = l + r >> 1;
        int res = -1;
        if(xl <= m) res = query(xl, xr, yl, yr, lson);
        if(xr > m) res = max(res, query(xl, xr, yl, yr, rson));
        return res;
    }
}
int main() {
    int t;
    while(scanf("%d", &t) && t) {
        n = 1000;
        build(100, 200, 1);
        while(t--) {
            char ch[2];
            int a, b;
            double c, d;
            scanf("%s", ch);
            if(ch[0] == 'I') {
                scanf("%d%lf%lf", &a, &c, &d);
                update(a, c * 10, d * 10, 100, 200, 1);
            } else {
                scanf("%d%d%lf%lf", &a, &b, &c, &d);
                int cc = c * 10, dd = d * 10;
                if(a > b) swap(a, b);
                if(cc > dd) swap(cc, dd);
                int ans = query(a, b, cc, dd, 100, 200, 1);
                if(ans == -1) printf("-1\n");
                else printf("%.1f\n", ans / 10.0);
            }
        }
    }
    return 0;
}
  1. 线段树合并

P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
#define P pair
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 1e5 + 10;
struct {
    int l, r, maxt,maxn;
}tree[N<<6];
struct query {
    int x, y, z;
}q[N];
vector >e(N);
int top[N], siz[N], son[N], deep[N], fa[N],root[N],ans[N],maxn=0,cnt=0;
void dfs1(int x, int father) {
    deep[x] = deep[father] + 1, siz[x] = 1, fa[x] = father;
    for (int i : e[x]) {
        if (i == father) continue;
        dfs1(i, x);
        siz[x] += siz[i];
        if (siz[i] > siz[son[x]]) son[x] = i;
    }
}
void dfs2(int x, int topx) {
    top[x] = topx;
    if (!son[x]) return;
    dfs2(son[x], topx);
    for (int i : e[x]) {
        if (i == fa[x] || i == son[x]) continue;
        dfs2(i, i);
    }
}
int lca(int x, int y) {
    while (top[x] != top[y]) {
        if (deep[top[x]] > deep[top[y]]) x = fa[top[x]];
        else y = fa[top[y]];
    }
    return deep[x] < deep[y] ? x : y;
}
void pushup(int x) {
    if (tree[tree[x].l].maxt >= tree[tree[x].r].maxt) {
        tree[x].maxt = tree[tree[x].l].maxt;
        tree[x].maxn = tree[tree[x].l].maxn;
    }
    else {
        tree[x].maxt = tree[tree[x].r].maxt;
        tree[x].maxn = tree[tree[x].r].maxn;
    }
}
void add(int& x, int l, int r, int pos, int k) {
    if (!x) x = ++cnt;
    if (l == r) {
        tree[x].maxt += k;
        tree[x].maxn = pos;
        return;
    }
    int mid = (l + r) >> 1;
    if (pos <= mid) add(tree[x].l, l, mid, pos, k);
    else add(tree[x].r, mid + 1, r, pos, k);
    pushup(x);
}
void merge(int& x, int y, int l, int r) {
    if (!x || !y) { x = x + y; return; }
    if (l == r) {
        tree[x].maxt += tree[y].maxt;
        tree[x].maxn = l;
        return;
    }
    int mid = (l + r) >> 1;
    merge(tree[x].l, tree[y].l, l, mid);
    merge(tree[x].r, tree[y].r, mid+1, r);
    pushup(x);
}
void dfs(int x, int father) {
    for (int i : e[x]) {
        if (i == father) continue;
        dfs(i, x);
        merge(root[x], root[i], 1, maxn);
    }
    if(tree[root[x]].maxt) ans[x] = tree[root[x]].maxn;
}
void solve() {
    int n, m;
    cin >> n >> m;
    for (int i = 1; i < n; ++i) {
        int u, v;
        cin >> u >> v;
        e[u].push_back(v);
        e[v].push_back(u);
    }
    dfs1(1, 0);
    dfs2(1, 1);
    for (int i = 1; i <= m; ++i) {
        cin >> q[i].x >> q[i].y >> q[i].z;
        maxn = max(maxn, q[i].z);
    }
    for (int i = 1; i <= m; ++i) {
        int d = lca(q[i].x, q[i].y);
        add(root[q[i].x], 1, maxn, q[i].z, 1);
        add(root[q[i].y], 1, maxn, q[i].z, 1);
        add(root[d], 1, maxn, q[i].z, -1);
        add(root[fa[d]], 1, maxn, q[i].z, -1);
    }
    dfs(1, 0);
    for (int i = 1; i <= n; ++i) cout << ans[i] << '\n';
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 线段树分裂

P5494 【模板】线段树分裂

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
#define P pair
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e9;
const ll N = 2e5 + 10;
struct node {
    int l, r;
    ll val;
}tr[N << 5];
int root[N], tot = 0, cnt = 1;
void add(int& p, int l, int r, int k, int pos) {
    if (!p) p = ++tot;
    tr[p].val += k;
    if (l == r) return;
    int mid = (l + r) >> 1;
    if (pos <= mid) add(tr[p].l, l, mid, k, pos);
    else add(tr[p].r, mid + 1, r, k, pos);
}
ll query(int p, int l, int r, int ql, int qr) {
    if (ql <= l && qr >= r) return tr[p].val;
    ll ans = 0;
    int mid = (l + r) >> 1;
    if (ql <= mid) ans += query(tr[p].l, l, mid, ql, qr);
    if (qr > mid) ans += query(tr[p].r, mid + 1, r, ql, qr);
    return ans;
}
int kth(int p, int l, int r, ll k) {
    if (l == r) return l;
    int mid = (l + r) >> 1;
    if (tr[tr[p].l].val >= k) return kth(tr[p].l, l, mid, k);
    else return kth(tr[p].r, mid + 1, r, k - tr[tr[p].l].val);
}
void merge(int& x, int y) {
    if (!x || !y) { x = x + y; return; }
    tr[x].val += tr[y].val;
    merge(tr[x].l, tr[y].l);
    merge(tr[x].r, tr[y].r);
}
void split(int x, int& y, ll k) {
    if (!x) return;
    y = ++tot;
    if (k > tr[tr[x].l].val) split(tr[x].r, tr[y].r, k - tr[tr[x].l].val);
    else swap(tr[x].r, tr[y].r);
    if (k < tr[tr[x].l].val) split(tr[x].l, tr[y].l, k);
    tr[y].val = tr[x].val - k;
    tr[x].val = k;
}
void solve() {
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) {
        int k;
        cin >> k;
        add(root[1], 1, n, k, i);
    }
    for (int i = 1; i <= m; ++i) {
        int op, p;
        cin >> op >> p;
        if (op == 0) {
            int x, y;
            cin >> x >> y;
            ll k1 = query(root[p], 1, n, x, y), k2 = query(root[p], 1, n, 1, y);
            int tmp = 0;
            split(root[p], tmp, k2);
            split(root[p], root[++cnt], k2 - k1);
            merge(root[p], tmp);
        }
        else if (op == 1) {
            int t;
            cin >> t;
            merge(root[p], root[t]);
        }
        else if (op == 2) {
            int k, q;
            cin >> k >> q;
            add(root[p], 1, n, k, q);
        }
        else if (op == 3) {
            int x, y;
            cin >> x >> y;
            cout << query(root[p], 1, n, x, y) << '\n';
        }
        else {
            ll k;
            cin >> k;
            if (k > tr[root[p]].val) cout << -1 << '\n';
            else cout << kth(root[p], 1, n, k) << '\n';
        }
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 线段树分治

P5787 二分图 /【模板】线段树分治

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
#define P pair
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 4e5 + 10;
struct edge {
    int u, v;
}e[N];
vector > t(N);
stack

st; int n, m, k, fa[N], cnt[N]; int find(int x) { if (x == fa[x]) return x; else return find(fa[x]); } void merge(int x, int y) { x = find(x), y = find(y); if (cnt[x] > cnt[y]) swap(x, y); st.push({ x, cnt[x] == cnt[y] }); if (cnt[x] == cnt[y]) cnt[y]++; fa[x] = y; } bool query(int x, int y) { return find(x) == find(y); } void modify(int x, int l, int r, int ql, int qr, int id) { if (ql <= l && qr >= r) { t[x].push_back(id); return; } int mid = l + r >> 1; if (ql <= mid) modify(x << 1, l, mid, ql, qr, id); if (qr > mid) modify(x << 1 | 1, mid + 1, r, ql, qr, id); } void query(int x, int l, int r) { bool f = 1; int last = st.size(); for (int i : t[x]) { if (query(e[i].u, e[i].v)) { for (int j = l; j <= r; ++j) cout << "No\n"; f = 0; break; } merge(e[i].u, e[i].v + n); merge(e[i].v, e[i].u + n); } if (f) { if (l == r) cout << "Yes\n"; else { int mid = l + r >> 1; query(x << 1, l, mid); query(x << 1 | 1, mid + 1, r); } } while (st.size() > last) { cnt[fa[st.top().first]] -= st.top().second; fa[st.top().first] = st.top().first; st.pop(); } } void solve() { cin >> n >> m >> k; for (int i = 1; i <= m; ++i) { cin >> e[i].u >> e[i].v; int l, r; cin >> l >> r; l++; modify(1, 1, k, l, r, i); } for (int i = 1; i <= 2 * n; ++i) fa[i] = i; query(1, 1, k); } int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int _t; _t = 1; //cin>>_t; while (_t--) { solve(); } return 0; }

  1. 可持久化线段树

P3919 【模板】可持久化线段树 1(可持久化数组)

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define LL long long 
#define P pair
const double eps = 1e-8;
const LL INF = 1e18;
const LL N = 1e6 + 10;
struct {
    int l, r,val;
}tree[N << 5];
LL a[N], b[N], root[N], cnt = 0;
int build(int l, int r) {
    int res = ++cnt;
    if (l == r) {
        tree[res].val = a[l];
        return res;
    }
    int mid = (l + r) >> 1;
    tree[res].l=build(l, mid);
    tree[res].r=build(mid + 1, r);
    return res;
}
int modify(int x, int l, int r, int index,LL k) {
    int res = ++cnt;
    if (l == r) {
        tree[res].val = k;
        return res;
    }
    tree[res].l = tree[x].l;
    tree[res].r = tree[x].r;
    int mid = (l + r) >> 1;
    if (index <= mid) tree[res].l = modify(tree[x].l, l, mid, index,k);
    else tree[res].r = modify(tree[x].r, mid + 1,r, index,k);
    return res;
}
LL query(int x, int l, int r, int index) {
    if (l == r) return tree[x].val;
    int mid = (l + r) >> 1;
    if (index<=mid) return query(tree[x].l, l, mid, index);
    else return query(tree[x].r, mid + 1, r, index);
}
void solve() {
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; ++i)  cin >> a[i];
    root[0]=build(1, n);
    for (int i = 1; i <= m; ++i) {
        int x, op, index;
        cin >> x >> op >> index;
        if (op == 1) {
            LL k;
            cin >> k;
            root[i]=modify(root[x], 1, n, index, k);
        }
        else {
            cout << query(root[x], 1, n, index) << '\n';
            root[i] = root[x];
        }
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. k大/小问题

P3834 【模板】可持久化线段树 2

建树

查询

空间

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define LL long long 
#define P pair
const double eps = 1e-8;
const LL INF = 1e18;
const LL N = 2e5 + 10;
struct {
    int l, r, sum;
}tree[N<<5];
LL a[N], b[N],root[N],cnt=0;
int modify(int x, int l, int r, int k) {
    int res = ++cnt;
    tree[res].l = tree[x].l;
    tree[res].r = tree[x].r;
    tree[res].sum = tree[x].sum + 1;
    int mid = (l + r) >> 1;
    if (l != r) {
        if (k <= mid) tree[res].l = modify(tree[x].l, l, mid, k);
        else tree[res].r = modify(tree[x].r, mid + 1, r, k);
    }
    return res;
}
LL query(int u, int v, int l, int r, int k) {
    if (l == r) return b[l];
    int x = tree[tree[u].l].sum - tree[tree[v].l].sum;
    int mid = (l + r) >> 1;
    if (x >= k) return query(tree[u].l, tree[v].l, l, mid, k);
    else return query(tree[u].r, tree[v].r, mid+1, r, k - x);
}
void solve() {
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
        b[i] = a[i];
    }
    sort(b + 1, b + n + 1);
    int size = unique(b + 1, b + n + 1) - b - 1;
    for (int i = 1; i <= n; ++i) {
        int k = lower_bound(b + 1, b + size + 1, a[i]) - b;
        root[i] = modify(root[i - 1], 1, size, k);
    }
    for (int i = 1; i <= m; ++i) {
        int l, r, k;
        cin >> l >> r >> k;
        cout << query(root[r], root[l - 1], 1, size, k)<<'\n';
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 树的重心

poj3107 Godfather

参考博客

#include
#include
#include
#include
using namespace std;
#define N 50005
#define inf 0x3f3f3f3f
struct node{
    int v,to;
} edge[N*2];
int cnt,x,y,n,sum,num,head[N],dp[N],ans[N];
void add(int u,int v){
    edge[++cnt].to=head[u];
    edge[cnt].v=v;
    head[u]=cnt;
}
void dfs(int u,int pre){
    dp[u]=1;
    int temp=0;
    for(int i=head[u]; i!=-1; i=edge[i].to){
        int v=edge[i].v;
        if(v==pre)continue;
        dfs(v,u);
        dp[u]+=dp[v];
        temp=max(temp,dp[v]);
    }
    temp=max(temp,n-dp[u]);
    if(temp
  1. 树的直径(dfs)

参考OI Wiki

不能用于带负权树

#include
using namespace std;
#define LL long long
const LL N = 1e4 + 10;
int n, c, d[N];
vector e(N);
void dfs(int u, int fa) {
  for (int v : e[u]) {
    if (v == fa) continue;
    d[v] = d[u] + 1;
    if (d[v] > d[c]) c = v;
    dfs(v, u);
  }
}

int main() {
  cin >> n;
  for (int i = 1; i < n; i++) {
    int u, v;
    cin >> u >> v;
    e[u].push_back(v);
    e[v].push_back(u);
  }
  dfs(1, 0);
  d[c] = 0, dfs(c, 0);
  cout << d[c];
  return 0;
}
  1. 树的直径(树形dp)

参考OI Wiki

无法得到完整路径

#include
using namespace std;
#define LL long long
const LL N = 1e4 + 10;
int n, d = 0, d1[N], d2[N];
vector e(N);
void dfs(int u, int fa) {
  d1[u] = d2[u] = 0;
  for (int v : e[u]) {
    if (v == fa) continue;
    dfs(v, u);
    int t = d1[v] + 1;
    if (t > d1[u])
      d2[u] = d1[u], d1[u] = t;
    else if (t > d2[u])
      d2[u] = t;
  }
  d = max(d, d1[u] + d2[u]);
}
int main() {
  cin >> n;
  for (int i = 1; i < n; i++) {
    int u, v;
    cin >> u >> v;
    e[u].push_back(v);
    e[v].push_back(u);
  }
  dfs(1, 0);
  cout << d;
  return 0;
}
  1. LCA(倍增)

P3379 【模板】最近公共祖先(LCA)

在线

预处理

查询

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define LL long long 
#define P pair
const double eps = 1e-8;
const LL INF = 1e18;
const LL N = 5e5 + 10;
int n, m, s, deep[N], fa[N][20];
vector >e(N);
void dfs(int x, int father) {
    deep[x] = deep[father] + 1;
    fa[x][0] = father;
    for (int i = 1; (1 << i) <= deep[x]; ++i) {
        fa[x][i] = fa[fa[x][i - 1]][i - 1];
    }
    for (int i : e[x]) {
        if (i == father) continue;
        dfs(i, x);
    }
}
int lca(int x, int y) {
    if (deep[x] <= deep[y]) swap(x, y);
    for (int i = 19; i >= 0; --i) {
        if (deep[x] - (1 << i) >= deep[y]) x = fa[x][i];
    }
    if (x == y) return x;
    for (int i = 19; i >= 0; --i) {
        if (fa[x][i] != fa[y][i]) {
            x = fa[x][i];
            y = fa[y][i];
        }
    }
    return fa[x][0];
}
void solve() {
    cin >> n >> m >> s;
    for (int i = 1; i < n; ++i) {
        int u, v;
        cin >> u >> v;
        e[u].push_back(v);
        e[v].push_back(u);
    }
    dfs(s, 0);
    for (int i = 1; i <= m; ++i) {
        int x, y;
        cin >> x >> y;
        cout << lca(x, y) << '\n';
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. LCA(tarjan)

P3379 【模板】最近公共祖先(LCA)

离线

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define LL long long 
#define P pair
const double eps = 1e-8;
const LL INF = 1e18;
const LL N = 5e5 + 10;
int n, m, s, ans[N], f[N], vis[N];
vector >e(N);
vector >q(N);
int find(int x) {
    if (f[x] == x) return x;
    return f[x] = find(f[x]);
}
void tarjan(int x) {
    vis[x] = 1;
    for (int i : e[x]) {
        if (vis[i] == 0) {
            tarjan(i);
            f[i] = x;
        }
    }
    for (P i : q[x]) {
        int u = i.first;
        if (vis[u]) ans[i.second] = find(u);
    }
}
void solve() {
    cin >> n >> m >> s;
    for (int i = 1; i <= n; ++i) f[i] = i;
    for (int i = 1; i < n; ++i) {
        int u, v;
        cin >> u >> v;
        e[u].push_back(v);
        e[v].push_back(u);
    }
    for (int i = 1; i <= m; ++i) {
        int x, y;
        cin >> x >> y;
        q[x].push_back(P(y, i));
        q[y].push_back(P(x, i));
    }
    tarjan(s);
    for (int i = 1; i <= m; ++i) cout << ans[i] << '\n';
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. LCA(重链剖分)

P3379 【模板】最近公共祖先(LCA)

在线

预处理

查询

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
#define P pair
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 5e5 + 10;
ll top[N], son[N], siz[N], fa[N], deep[N];
vector >e(N);
void dfs1(int x, int father) {
    deep[x] = deep[father] + 1, siz[x] = 1, fa[x] = father;
    for (int i : e[x]) {
        if (i == father) continue;
        dfs1(i, x);
        siz[x] += siz[i];
        if (siz[son[x]] < siz[i]) son[x] = i;
    }
}
void dfs2(int x, int topx) {
    top[x] = topx;
    if (!son[x]) return;
    dfs2(son[x], topx);
    for (int i : e[x]) {
        if (i == fa[x] || i == son[x]) continue;
        dfs2(i, i);
    }
}
int lca(int x, int y) {
    while (top[x] != top[y]) {
        if (deep[top[x]] >= deep[top[y]]) x = fa[top[x]];
        else y = fa[top[y]];
    }
    return deep[x] < deep[y] ? x : y;
}
void solve() {
    int n, m,s;
    cin >> n >> m>>s;
    for (int i = 1; i < n; ++i) {
        int u, v;
        cin >> u >> v;
        e[u].push_back(v);
        e[v].push_back(u);
    }
    dfs1(s, 0);
    dfs2(s, s);
    for (int i = 1; i <= m; ++i) {
        int x, y;
        cin >> x >> y;
        cout << lca(x, y) << '\n';
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 树上差分

P3128 [USACO15DEC]Max Flow P

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define LL long long 
#define P pair
const double eps = 1e-8;
const LL INF = 1e18;
const LL N = 5e4 + 10;
int n, m,ans=0, deep[N], fa[N][20],d[N];
vector >e(N);
void dfs1(int x, int father) {
    deep[x] = deep[father] + 1;
    fa[x][0] = father;
    for (int i = 1; (1 << i) <= deep[x]; ++i) {
        fa[x][i] = fa[fa[x][i - 1]][i - 1];
    }
    for (int i : e[x]) {
        if (i == father) continue;
        dfs1(i, x);
    }
}
int lca(int x, int y) {
    if (deep[x] <= deep[y]) swap(x, y);
    for (int i = 19; i >= 0; --i) {
        if (deep[x] - (1 << i) >= deep[y]) x = fa[x][i];
    }
    if (x == y) return x;
    for (int i = 19; i >= 0; --i) {
        if (fa[x][i] != fa[y][i]) {
            x = fa[x][i];
            y = fa[y][i];
        }
    }
    return fa[x][0];
}
void dfs2(int x,int father) {
    for (int i : e[x]) {
        if (i == father) continue;
        dfs2(i, x);
        d[x] += d[i];
    }
    ans = max(ans, d[x]);
}
void solve() {
    cin >> n >> m;
    for (int i = 1; i < n; ++i) {
        int u, v;
        cin >> u >> v;
        e[u].push_back(v);
        e[v].push_back(u);
    }
    dfs1(1, 0);
    for (int i = 1; i <= m; ++i) {
        int x, y;
        cin >> x >> y;
        int u=lca(x, y);
        d[x]++;
        d[y]++;
        d[u]--;
        d[fa[u][0]]--;
    }
    dfs2(1,0);
    cout << ans;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 基础莫队

P1972 [SDOI2009] HH的项链

该题卡莫队,快读快写48pts,主要看思想

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define LL long long 
#define P pair
const double eps = 1e-8;
const LL INF = 1e18;
const LL MAXN = 1e6 + 10;
int a[MAXN], block, belong[MAXN], ans[MAXN], cnt[MAXN], Ans = 0;
char buf[10];
struct query {
    int l, r, id;
    bool operator < (const query a)const {
        return belong[l] == belong[a.l] ? belong[l] % 2 ? ra.r : belong[l] < belong[a.l];
    }
}q[MAXN];
inline int read() {
    int res = 0;
    char ch = getchar();
    while (ch < '0' || ch>'9') ch = getchar();
    while (ch >= '0' && ch <= '9') { res = (res << 3) + (res << 1) + (ch ^ 48); ch = getchar(); }
    return res;
}
inline void write(int x) {
    int pos = 0;
    while (x) {
        buf[++pos] = x % 10 + '0';
        x /= 10;
    }
    while (pos--) putchar(buf[pos+1]);
    putchar('\n');
}
inline void Add(int pos) {
    cnt[a[pos]]++;
    if (cnt[a[pos]] == 1) Ans++;
}
inline void Delete(int pos) {
    cnt[a[pos]]--;
    if (cnt[a[pos]] == 0) Ans--;
}
inline void solve() {
    int n, m;
    n = read();
    block = sqrt(n);
    for (int i = 1; i <= n; ++i) {
        a[i] = read();
        belong[i] = (i - 1) / block + 1;
    }
    m = read();
    for (int i = 1; i <= m; ++i) {
        int l, r;
        q[i].l = read(), q[i].r = read();
        q[i].id = i;
    }
    sort(q + 1, q + m + 1);
    int L = 1, R = 0;
    for (int i = 1; i <= m; ++i) {
        while (L < q[i].l) Delete(L++);
        while (R > q[i].r) Delete(R--);
        while (L > q[i].l) Add(--L);
        while (R < q[i].r) Add(++R);
        ans[q[i].id] = Ans;
    }
    for (int i = 1; i <= m; ++i) write(ans[i]);
}
int main() {
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 带修莫队

P1903 [国家集训队] 数颜色 / 维护队列

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
#define P pair
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 1e6 + 10;
int a[N], block, belong[N], ans[N], cnt[N], Ans = 0;
struct {
    int p, c;
}p[N];
struct query{
    int l, r, t, id;
    bool operator<(const query a) {
        return belong[l] == belong[a.l] ? belong[r] == belong[a.r] ? t < a.t : belong[r] < belong[a.r] : belong[l] < belong[a.l];
    }
}q[N];
void del(int x) {
    cnt[x]--;
    if (cnt[x] == 0) Ans--;
}
void add(int x) {
    cnt[x]++;
    if (cnt[x] == 1) Ans++;
}
void modify(int x,int t) {
    if (p[t].p >= q[x].l && p[t].p <= q[x].r) {
        del(a[p[t].p]);
        add(p[t].c);
    }
    swap(a[p[t].p], p[t].c);
}
void solve() {
    int n, m;
    cin >> n >> m;
    block = pow(n, 0.666666);
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
        belong[i] = (i - 1) / block + 1;
    }
    int cnt1 = 0, cnt2 = 0;
    for (int i = 1; i <= m; ++i) {
        char ch;
        cin >> ch;
        if (ch == 'Q') {
            cin >> q[++cnt1].l >> q[cnt1].r;
            q[cnt1].t = cnt2, q[cnt1].id = cnt1;
        }
        else {
            cin >> p[++cnt2].p >> p[cnt2].c;
        }
    }
    int L = 1, R = 0, cur = 0;
    sort(q + 1, q + cnt1 + 1);
    for (int i = 1; i <= cnt1; ++i) {
        while (L < q[i].l) del(a[L++]);
        while (R > q[i].r) del(a[R--]);
        while (L > q[i].l) add(a[--L]);
        while (R < q[i].r) add(a[++R]);
        while (cur < q[i].t) modify(i,++cur);
        while (cur > q[i].t) modify(i,cur--);
        ans[q[i].id] = Ans;
    }
    for (int i = 1; i <= cnt1; ++i) cout << ans[i] << '\n';
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 树上莫队

COT2 - Count on a tree II

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
#define P pair
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 1e5 + 10;
ll a[N], b[N], vis[N], belong[N],cnt[N], st[N], ed[N], pos[N], top[N], son[N], siz[N], fa[N], deep[N], ans[N], block, Ans = 0, tot = 0;
struct query {
    int l, r, lca,id;
    bool operator<(const query a) const {
        return belong[l] == belong[a.l] ? r < a.r : belong[l] < belong[a.l];
    }
}q[N];
vector >e(N);
void dfs1(int x,int father) {
    deep[x] = deep[father] + 1, siz[x] = 1, fa[x] = father, st[x] = ++tot, pos[tot] = x;
    for (int i : e[x]) {
        if (i == father) continue;
        dfs1(i,x);
        siz[x] += siz[i];
        if (siz[son[x]] < siz[i]) son[x] = i;
    }
    ed[x] = ++tot, pos[tot] = x;
}
void dfs2(int x, int topx) {
    top[x] = topx;
    if (!son[x]) return;
    dfs2(son[x], topx);
    for (int i : e[x]) {
        if (i == fa[x] || i == son[x]) continue;
        dfs2(i, i);
    }
}
int lca(int x, int y) {
    while (top[x] != top[y]) {
        if (deep[top[x]] >= deep[top[y]]) x = fa[top[x]];
        else y = fa[top[y]];
    }
    return deep[x] < deep[y] ? x : y;
}
void modify(int x) {
    if (vis[x]) {
        cnt[a[x]]--;
        if (cnt[a[x]] == 0) Ans--;
    }
    else {
        cnt[a[x]]++;
        if (cnt[a[x]] == 1) Ans++;
    }
    vis[x] ^= 1;
}
void solve() {
    int n, m;
    cin >> n >> m;
    block = sqrt(n);
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
        b[i] = a[i];
    }
    for (int i = 1; i <= 2 * n; ++i) belong[i] = (i - 1) / block + 1;
    sort(b + 1, b + n + 1);
    int len = unique(b + 1, b + n + 1) - b-1;
    for (int i = 1; i <= n; ++i) a[i] = lower_bound(b + 1, b + len + 1, a[i]) - b;
    for (int i = 1; i < n; ++i) {
        int u, v;
        cin >> u >> v;
        e[u].push_back(v);
        e[v].push_back(u);
    }
    dfs1(1,0);
    dfs2(1,1);
    for (int i = 1; i <= m; ++i) {
        int x, y;
        cin >> x >> y;
        if (st[x] > st[y]) swap(x, y);
        int d = lca(x, y);
        if (d == x) q[i].l = st[x], q[i].r = st[y];
        else q[i].l = ed[x], q[i].r = st[y], q[i].lca = d;
        q[i].id = i;
    }
    sort(q + 1, q + m + 1);
    int L = 1, R = 0;
    for (int i = 1; i <= m; ++i) {
        while (L < q[i].l) modify(pos[L++]);
        while (R > q[i].r) modify(pos[R--]);
        while (L > q[i].l) modify(pos[--L]);
        while (R < q[i].r) modify(pos[++R]);
        if (q[i].lca) modify(q[i].lca);
        ans[q[i].id] = Ans;
        if (q[i].lca) modify(q[i].lca);
    }
    for (int i = 1; i <= m; ++i) cout << ans[i] << '\n';
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 回滚莫队

P5906 【模板】回滚莫队&不删除莫队

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
#define P pair
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 2e5 + 10;
int a[N], b[N], belong[N], st[N], ed[N], ed2[N], ans[N], block;
struct query {
    int l, r, id;
    bool operator<(const query a)const {
        return belong[l] == belong[a.l] ? r < a.r : belong[l] < belong[a.l];
    }
}q[N];
void solve() {
    int n, m;
    cin >> n;
    block = sqrt(n);
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
        b[i] = a[i];
        belong[i] = (i - 1) / block + 1;
    }
    sort(b + 1, b + n + 1);
    int len = unique(b + 1, b + n + 1) - b - 1;
    for (int i = 1; i <= n; ++i) a[i] = lower_bound(b + 1, b + len + 1, a[i]) - b;
    cin >> m;
    for (int i = 1; i <= m; ++i) {
        cin >> q[i].l >> q[i].r;
        q[i].id = i;
    }
    sort(q + 1, q + m + 1);
    int last = 0, L=1, R=0,Ans1,Ans2;
    for (int i = 1; i <= m; ++i) {
        if (belong[q[i].l] == belong[q[i].r]) {
            Ans1 = 0;
            for (int j = q[i].l; j <= q[i].r; ++j) st[a[j]] = 0;
            for (int j = q[i].l; j <= q[i].r; ++j) {
                if (!st[a[j]]) st[a[j]] = j;
                Ans1 = max(Ans1, j - st[a[j]]);
            }
            for (int j = q[i].l; j <= q[i].r; ++j) st[a[j]] = 0;
            ans[q[i].id] = Ans1;
        }
        else {
            if (belong[q[i].l] != last) {
                Ans1 = 0;
                for (int j = L; j <= R; ++j) st[a[j]] = ed[a[j]] = 0;
                L = belong[q[i].l] * block;
                R = L - 1;
                last = belong[q[i].l];
            }
            while (R < q[i].r) {
                R++;
                if (!st[a[R]]) st[a[R]] = R;
                ed[a[R]] = R;
                Ans1 = max(Ans1, R - st[a[R]]);
            }
            int p = L;
            Ans2 = 0;
            while (q[i].l < p) {
                p--;
                if (!ed2[a[p]]) ed2[a[p]] = p;
                Ans2 = max(Ans2, max(ed[a[p]], ed2[a[p]]) - p);
            }
            for (int j = p; j < L; ++j) ed2[a[j]] = 0;
            ans[q[i].id] = max(Ans1,Ans2);
        }
    }
    for (int i = 1; i <= m; ++i) cout << ans[i] << '\n';
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 二次离线莫队

P4887 【模板】莫队二次离线(第十四分块(前体))

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
#define P pair
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 1e5 + 10;
int a[N],  belong[N], cnt[N], pre[N], block;
ll ans[N];
struct query {
    int l, r, id;
    ll ans;
    bool operator<(const query a)const {
        return belong[l] == belong[a.l] ? r < a.r : belong[l] < belong[a.l];
    }
}q[N];
vector v;
vector > >p(N);
int bitcount(int x) {
    int res = 0;
    while (x) {
        if (x & 1) res++;
        x >>= 1;
    }
    return res;
}
void solve() {
    int n, m, k;
    cin >> n >> m >> k;
    if (k > 14) {
        for (int i = 1; i <= m; ++i) cout << 0 << '\n';
        return;
    }
    block = sqrt(n);
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
        belong[i] = (i - 1) / block + 1;
    }
    for (int i = 0; i < 16384; ++i) {
        if (bitcount(i) == k) v.push_back(i);
    }
    for (int i = 1; i <= n; ++i) {
        for (int j : v) cnt[a[i] ^ j]++;
        pre[i] = cnt[a[i + 1]];
    }
    memset(cnt, 0, sizeof(cnt));
    for (int i = 1; i <= m; ++i) {
        cin >> q[i].l >> q[i].r;
        q[i].id = i;
    }
    sort(q + 1, q + m + 1);
    int L = 1, R = 0;
    for (int i = 1; i <= m; ++i) {
        ll Ans = 0;
        if (L < q[i].l) p[R].push_back({ L, q[i].l - 1, -i });
        while (L < q[i].l) {
            Ans += pre[L - 1];
            L++;
        }
        if (L > q[i].l) p[R].push_back({ q[i].l, L - 1, i });
        while (L > q[i].l) {
            L--;
            Ans -= pre[L - 1];
        }
        if (R < q[i].r) p[L - 1].push_back({ R + 1, q[i].r, -i });
        while (R < q[i].r) {
            R++;
            Ans += pre[R - 1];
        }
        if (R > q[i].r) p[L - 1].push_back({ q[i].r + 1,R,i });
        while (R > q[i].r) {
            Ans -= pre[R - 1];
            R--;
        }
        q[i].ans = Ans;
    }
    for (int i = 1; i <= n; ++i) {
        for (int j : v) cnt[a[i] ^ j]++;
        for (auto t : p[i]) {
            int l, r, id;
            tie(l, r, id) = t;
            for (int j = l; j <= r; ++j) {
                int temp = cnt[a[j]];
                if (j <= i && k == 0) temp--;
                if (id < 0) q[-id].ans -= temp;
                else q[id].ans += temp;
            }
        }
    }
    for (int i = 1; i <= m; ++i) q[i].ans += q[i - 1].ans;
    for (int i = 1; i <= m; ++i) ans[q[i].id] = q[i].ans;
    for (int i = 1; i <= m; ++i) cout << ans[i] << '\n';
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 块状链表

P4008 [NOI2003] 文本编辑器

参考《算法竞赛》

#include
#include
#include 
#include 
using namespace std;
#define it list >::iterator
int block = 2500;
list > List;
it Next(it x) {
    return ++x;
}
it Find(int& x) {
    for (it i = List.begin(); ; ++i) {
        if (i==List.end()||x <= i->size()) return i;
        x -= i->size();
    }
}
void Output(int l, int r) {
    it L = Find(l), R = Find(r);
    if (L == R) {
        for (int i = l; i < r; ++i) {
            cout << L->at(i);
        }
    }
    else {
        for (int i = l; i < L->size(); ++i) cout << L->at(i);
        for (++L; L != R; ++L) {
            for (int i = 0; i < L->size(); ++i) cout << L->at(i);
        }
        for (int i = 0; i < r; ++i) cout << R->at(i);
    }
    cout << '\n';
}
void Merge(it x) {
    x->insert(x->end(), Next(x)->begin(), Next(x)->end());
    List.erase(Next(x));
}
void Split(it x, int pos) {
    if (pos == x->size()) return;
    List.insert(Next(x), vector(x->begin() + pos, x->end()));
    x->erase(x->begin() + pos, x->end());
}
void Update() {
    for (it i = List.begin(); i != List.end(); ++i) {
        while (i->size() >= (block << 1)) Split(i, i->size() - block);
        while (Next(i) != List.end() && i->size() + Next(i)->size() <= block) Merge(i);
        while (Next(i) != List.end() && Next(i)->empty()) List.erase(Next(i));
    }
}
void Insert(int pos, const vector& ch) {
    it cur = Find(pos);
    if (!List.empty()) {
        Split(cur, pos);
        List.insert(Next(cur), ch);
    }
    else List.insert(cur, ch);
    Update();
}
void Delete(int l, int r) {
    it L, R;
    L = Find(l), Split(L, l);
    R = Find(r), Split(R, r);
    R++;
    while (Next(L) != R) List.erase(Next(L));
    Update();
}
int main() {
    int n, len, pos=0;
    vector ch;
    cin >> n;
    while (n--) {
        string op;
        cin >> op;
        switch (op[0]) {
        case 'M':
            cin >> pos;
            break;
        case 'I':
            cin >> len;
            ch.clear(), ch.resize(len);
            for (int i = 0; i < len; ++i) {
                ch[i] = getchar();
                while (ch[i] < 32 || ch[i] >126) ch[i] = getchar();
            }
            Insert(pos, ch);
            break;
        case 'D':
            cin >> len;
            Delete(pos, pos + len);
            break;
        case 'G':
            cin >> len;
            Output(pos, pos + len);
            break;
        case 'P':
            --pos;
            break;
        case 'N':
            ++pos;
            break;
        }
    }
    return 0;
}
  1. 点分治

P3806 【模板】点分治1

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define LL long long 
#define P pair
const double eps = 1e-8;
const LL INF = 1e18;
const LL MAXN = 1e4 + 10;
const LL MAXM = 1e2 + 10;
struct edge {
    int u, v, w;
    edge(int u,int v,int w):u(u),v(v),w(w){}
};
vector >e(MAXN);
int n, m,root,minroot,cnt,q[MAXM],ans[MAXM],siz[MAXN],vis[MAXN],dis[MAXN],belong[MAXN],a[MAXN];
bool cmp(int a, int b) {
    return dis[a] < dis[b];
}
void getroot(int x,int fa,int sum) {
    siz[x] = 1;
    int num = 0;
    for (edge i : e[x]) {
        if (i.v == fa||vis[i.v]) continue;
        getroot(i.v, x,sum);
        siz[x] += siz[i.v];
        num = max(num, siz[i.v]);
    }
    num = max(num, sum - siz[x]);
    if (num < minroot) {
        minroot = num;
        root = x;
    }
}
void getdis(int x, int fa,int b) {
    a[++cnt] = x;
    belong[x] = b;
    for (edge i : e[x]) {
        if (i.v == fa || vis[i.v]) continue;
        dis[i.v] = dis[x] + i.w;
        getdis(i.v, x,b);
    }
}
void calc(int x) {
    cnt = 0;
    a[++cnt] = x;
    dis[x] = 0;
    belong[x] = x;
    for (edge i : e[x]) {
        if (vis[i.v]) continue;
        dis[i.v] = i.w;
        getdis(i.v, x, i.v);
    }
    sort(a + 1, a + cnt + 1, cmp);
    for (int i = 1; i <= m; ++i) {
        if (ans[i]) continue;
        int L = 1, R = cnt;
        while (L < R) {
            if (dis[a[L]] + dis[a[R]] < q[i]) L++;
            else if (dis[a[L]] + dis[a[R]] > q[i]) R--;
            else if (belong[a[L]] == belong[a[R]]) {
                if (dis[a[R]] == dis[a[R - 1]]) R--;
                else L++;
            }
            else {
                ans[i] = 1;
                break;
            }
        }
    }
}
void divide(int x) {
    vis[x] = 1;
    calc(x);
     for (edge i : e[root]) {
        if (vis[i.v]) continue;
        minroot = 0x3f3f3f3f;
        getroot(i.v, x, siz[i.v]);
        divide(root);
    }
}
void solve() {
    cin >> n >> m;
    for (int i = 1; i < n; ++i) {
        int u, v, w;
        cin >> u >> v >> w;
        e[u].push_back(edge(u, v, w));
        e[v].push_back(edge(v, u, w));
    }
    for (int i = 1; i <= m; ++i) {
        cin >> q[i];
    }
    minroot = 0x3f3f3f3f;
    getroot(1,0,n);
    divide(root);
    for (int i = 1; i <= m; ++i) {
        if (ans[i]) cout << "AYE\n";
        else cout << "NAY\n";
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 边分治

待填

  1. 点分树

P6329 【模板】点分树 | 震波

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define LL long long 
#define P pair
const double eps = 1e-8;
const LL INF = 1e9;
const LL N = 1e5 + 10;
vector < vector >e(N);
int n, m, ans, rt, sum, minn;
int val[N], siz[N], fa[N], deep[N], f[N][20];
bool vis[N];
vectorC[2][N];
void dfs0(int x, int fa) {
    f[x][0] = fa;
    deep[x] = deep[fa] + 1;
    for (int i = 1; (1 << i) <= deep[x]; ++i) f[x][i] = f[f[x][i - 1]][i - 1];
    for (int i : e[x]) {
        if (i == fa) continue;
        dfs0(i, x);
    }
}
int lca(int x, int y) {
    if (deep[x] < deep[y]) swap(x, y);
    for (int i = 19; i >= 0; --i) if (deep[f[x][i]] >= deep[y]) x = f[x][i];
    if (x == y) return x;
    for (int i = 19; i >= 0; --i) {
        if (f[x][i] != f[y][i]) {
            x = f[x][i];
            y = f[y][i];
        }
    }
    return f[x][0];
}
int getdis(int x, int y) {
    return deep[x] + deep[y] - 2 * deep[lca(x, y)];
}
int lowbit(int x) {
    return x & -x;
}
void add(int u, int opt, int x, int k) {
    x++;
    for (; x <= siz[u]; x += lowbit(x)) C[opt][u][x] += k;
}
int query(int u, int opt, int x) {
    x++;
    int res = 0;
    x = min(x, siz[u]);
    for (; x; x -= lowbit(x)) res += C[opt][u][x];
    return res;
}
void findrt(int x, int fa) {
    siz[x] = 1;
    int res = 0;
    for (int i : e[x]) {
        if (i != fa && !vis[i]) {
            findrt(i, x);
            siz[x] += siz[i], res = max(res, siz[i]);
        }
    }
    res = max(res, sum - siz[x]);
    if (res < minn) minn = res, rt = x;
}
void dfs(int x) {
    vis[x] = 1;
    siz[x] = sum + 1;
    C[0][x].resize(siz[x] + 1);
    C[1][x].resize(siz[x] + 1);
    for (int i : e[x]) {
        if (!vis[i]) {
            sum = siz[i], rt = 0, minn = INF;
            findrt(i, 0);
            fa[rt] = x;
            dfs(rt);
        }
    }
}
void modify(int x, int k) {
    for (int i = x; i; i = fa[i]) add(i, 0, getdis(x, i), k);
    for (int i = x; fa[i]; i = fa[i]) add(i, 1, getdis(x, fa[i]), k);
}
int main() {
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) cin >> val[i];
    for (int i = 1; i < n; ++i) {
        int u, v;
        cin >> u >> v;
        e[u].push_back(v);
        e[v].push_back(u);
    }
    dfs0(1, 0);
    sum = n, minn = INF;
    findrt(1, 0);
    dfs(rt);
    for (int i = 1; i <= n; ++i) modify(i, val[i]);
    for (int i = 1; i <= m; ++i) {
        int op, x, y;
        cin >> op >> x >> y;
        x ^= ans, y ^= ans;
        if (op == 0) {
            ans = 0;
            ans += query(x, 0, y);
            for (int i = x; fa[i]; i = fa[i]) {
                int dis = getdis(x, fa[i]);
                if (y >= dis) ans += query(fa[i], 0, y - dis) - query(i, 1, y - dis);
            }
            cout << ans << '\n';
        }
        else modify(x, y - val[x]), val[x] = y;
    }
    return 0;
}
  1. 重链剖分

P3384 【模板】重链剖分/树链剖分

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define LL long long 
#define P pair
const double eps = 1e-8;
const LL INF = 1e18;
const LL N = 1e5 + 10;
vector >e(N);
int n, m, root, p;
int val[N], nval[N], top[N], tag[N << 2], sum[N << 2], sze[N << 2], f[N], siz[N], deep[N], son[N], id[N], cnt = 0;
void dfs1(int x, int fa) {
    deep[x] = deep[fa] + 1;
    siz[x] = 1;
    f[x] = fa;
    for (int i : e[x]) {
        if (i == fa) continue;
        dfs1(i, x);
        siz[x] += siz[i];
        if (siz[son[x]] < siz[i]) son[x] = i;
    }
}
void dfs2(int x, int topx) {
    id[x] = ++cnt;
    nval[cnt] = val[x];
    top[x] = topx;
    if (!son[x]) return;
    dfs2(son[x], topx);
    for (int i : e[x]) {
        if (i == son[x] || i == f[x]) continue;
        dfs2(i, i);
    }
}
void pushup(int x) {
    sum[x] = (sum[x << 1] + sum[x << 1 | 1]) % p;
}
void pushtag(int x, int k) {
    sum[x] = (sum[x] + k * sze[x]) % p;
    tag[x] = (tag[x] + k) % p;
}
void pushdown(int x) {
    if (tag[x]) {
        pushtag(x << 1, tag[x]);
        pushtag(x << 1 | 1, tag[x]);
        tag[x] = 0;
    }
}
void build(int x, int l, int r) {
    if (l == r) {
        sum[x] = nval[l] % p;
        sze[x] = 1;
        return;
    }
    int mid = (l + r) >> 1;
    build(x << 1, l, mid);
    build(x << 1 | 1, mid + 1, r);
    sze[x] = sze[x << 1] + sze[x << 1 | 1];
    pushup(x);
}
void treemodify(int x, int l, int r, int ql, int qr, int k) {
    if (ql <= l && qr >= r) {
        pushtag(x, k);
        return;
    }
    pushdown(x);
    int mid = (l + r) >> 1;
    if (ql <= mid) treemodify(x << 1, l, mid, ql, qr, k);
    if (qr > mid) treemodify(x << 1 | 1, mid + 1, r, ql, qr, k);
    pushup(x);
}
LL treequery(int x, int l, int r, int ql, int qr) {
    if (ql <= l && qr >= r) return sum[x] % p;
    LL res = 0;
    pushdown(x);
    int mid = (l + r) >> 1;
    if (ql <= mid) res = (res + treequery(x << 1, l, mid, ql, qr)) % p;
    if (qr > mid) res = (res + treequery(x << 1 | 1, mid + 1, r, ql, qr)) % p;
    return res;
}
void modify(int x, int y, int k) {
    while (top[x] != top[y]) {
        if (deep[top[x]] < deep[top[y]]) swap(x, y);
        treemodify(1, 1, n, id[top[x]], id[x], k);
        x = f[top[x]];
    }
    if (deep[x] > deep[y]) swap(x, y);
    treemodify(1, 1, n, id[x], id[y], k);
}
LL query(int x, int y) {
    LL res = 0;
    while (top[x] != top[y]) {
        if (deep[top[x]] < deep[top[y]]) swap(x, y);
        res = (res + treequery(1, 1, n, id[top[x]], id[x])) % p;
        x = f[top[x]];
    }
    if (deep[x] > deep[y]) swap(x, y);
    res = (res + treequery(1, 1, n, id[x], id[y])) % p;
    return res;
}
void solve() {
    cin >> n >> m >> root >> p;
    for (int i = 1; i <= n; ++i) cin >> val[i];
    for (int i = 1; i < n; ++i) {
        int u, v;
        cin >> u >> v;
        e[u].push_back(v);
        e[v].push_back(u);
    }
    dfs1(root, 0);
    dfs2(root, root);
    build(1, 1, n);
    for (int i = 1; i <= m; ++i) {
        int op;
        cin >> op;
        if (op == 1) {
            int x, y, k;
            cin >> x >> y >> k;
            modify(x, y, k);
        }
        else if (op == 2) {
            int x, y;
            cin >> x >> y;
            cout << query(x, y) << '\n';
        }
        else if (op == 3) {
            int x, k;
            cin >> x >> k;
            treemodify(1, 1, n, id[x], id[x] + siz[x] - 1, k);
        }
        else {
            int x;
            cin >> x;
            cout << treequery(1, 1, n, id[x], id[x] + siz[x] - 1) << '\n';
        }
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 长链剖分

P5903 【模板】树上 k 级祖先

预处理

查询

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
#define P pair
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 5e5 + 10;
#define ui unsigned int
ui s;
inline ui get(ui x) {
    x ^= x << 13;
    x ^= x >> 17;
    x ^= x << 5;
    return s = x;
}
int deep[N], son[N], top[N], f[N][20], siz[N], bin[N];
vector > e(N), up(N), down(N);
void dfs1(int x) {
    deep[x] = deep[f[x][0]] + 1, siz[x] = 1;
    for (int i = 1; (1 << i) <= deep[x]; ++i) f[x][i] = f[f[x][i - 1]][i - 1];
    for (int i : e[x]) {
        dfs1(i);
        siz[x] = max(siz[x], siz[i] + 1);
        if (siz[i] > siz[son[x]]) son[x] = i;
    }
}
void dfs2(int x, int topx) {
    top[x] = topx;
    down[topx].push_back(x);
    if (!son[x]) return;
    dfs2(son[x], topx);
    for (int i : e[x]) {
        if (i == son[x]) continue;
        int temp = i;
        up[i].push_back(i);
        for (int j = 1; j <= siz[i]; ++j) {
            up[i].push_back(f[temp][0]);
            temp = f[temp][0];
        }
        dfs2(i, i);
    }
}
void solve() {
    int n, q, root;
    cin >> n >> q >> s;
    for (int i = 1; i <= n; ++i) {
        cin >> f[i][0];
        if (!f[i][0]) root = i;
        else e[f[i][0]].push_back(i);
        bin[i] = log2(i);
    }
    dfs1(root);
    dfs2(root, root);
    int temp = root;
    up[root].push_back(root);
    for (int i = 1; i <= siz[root]; ++i) {
        up[root].push_back(f[temp][0]);
        temp = f[temp][0];
    }
    ll last = 0, ans = 0;
    for (int i = 1; i <= q; ++i) {
        int x = (get(s) ^ last) % n + 1, k = (get(s) ^ last) % deep[x];
        if (k == 0) {
            last = x;
            ans ^= (1ll * i * x);
            continue;
        }
        int goal = deep[x] - k;
        x = top[f[x][bin[k]]];
        if (deep[x] < goal) x = down[x][goal - deep[x]];
        else x = up[x][deep[x] - goal];
        last = x;
        ans ^= (1ll * i * x);
    }
    cout << ans;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 启发式合并

P3201 [HNOI2009] 梦幻布丁

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
#define P pair
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 1e6 + 10;
int a[N],mp[N],ans=0;
vector >e(N);
void merge(int& x, int& y) {
    if (x == y) return;
    if (e[x].size() > e[y].size()) swap(x, y);
    for (int i : e[x]) {
        if (a[i - 1] == y) ans--;
        if (a[i + 1] == y) ans--;
    }
    for (int i : e[x]) a[i] = y;
    e[y].insert(e[y].end(), e[x].begin(), e[x].end());
    e[x].clear();
}
void solve() {
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <=n; ++i) {
        cin >> a[i], mp[a[i]] = a[i];
        e[a[i]].push_back(i);
    }
    for (int i = 1; i <= n; ++i) {
        if (a[i - 1] != a[i]) ans++;
    }
    for (int i = 1; i <= m; ++i) {
        int op;
        cin >> op;
        if (op == 1) {
            int x, y;
            cin >> x >> y;
            merge(mp[x], mp[y]);
        }
        else cout << ans << '\n';
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin >> _t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 树上启发式合并

CF600E Lomsat gelral

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
#define P pair
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 1e5 + 10;
int son[N], siz[N], color[N], cnt[N];
ll ans[N], maxn = 0, sum = 0;
vector >e(N);
void dfs1(int x, int father) {
    siz[x] = 1;
    for (int i : e[x]) {
        if (i == father) continue;
        dfs1(i, x);
        siz[x] += siz[i];
        if (siz[i] > siz[son[x]]) son[x] = i;
    }
}
void modify(int x, int father, int k, int pson) {
    int c = color[x];
    cnt[c] += k;
    if (cnt[c] > maxn) {
        maxn = cnt[c];
        sum = c;
    }
    else if (cnt[c] == maxn) sum += c;
    for (int i : e[x]) {
        if (i == father || i == pson) continue;
        modify(i, x, k, pson);
    }
}
void dfs2(int x, int father, int op) {
    for (int i : e[x]) {
        if (i == father || i == son[x]) continue;
        dfs2(i, x, 0);
    }
    if (son[x]) dfs2(son[x], x, 1);
    modify(x, father, 1, son[x]);
    ans[x] = sum;
    if (op == 0) {
        modify(x, father, -1, 0);
        maxn = sum = 0;
    }
}
void solve() {
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i) cin >> color[i];
    for (int i = 1; i < n; ++i) {
        int u, v;
        cin >> u >> v;
        e[u].push_back(v);
        e[v].push_back(u);
    }
    dfs1(1, 0);
    dfs2(1, 0, 1);
    for (int i = 1; i <= n; ++i) cout << ans[i] << " ";
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin >> _t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 替罪羊树

P3369 【模板】普通平衡树

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
#define P pair
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 1e5 + 10;
const double alpha = 0.7;
struct node {
    int l, r, key, siz, tot, del;
}tr[N];
int st[N], order[N];
int root = 0, cnt, tot = 0;
void initnode(int x) {
    tr[x].l = tr[x].r = 0;
    tr[x].siz = tr[x].tot = tr[x].del = 1;
}
void pushup(int x) {
    tr[x].siz = tr[tr[x].l].siz + tr[tr[x].r].siz + 1;
    tr[x].tot = tr[tr[x].l].tot + tr[tr[x].r].tot + 1;
}
bool notbalance(int x) {
    if ((double)tr[x].siz * alpha <= (double)max(tr[tr[x].l].siz, tr[tr[x].r].siz)) return 1;
    else return 0;
}
void inorder(int x) {
    if (!x) return;
    inorder(tr[x].l);
    if (tr[x].del) order[++cnt] = x;
    else st[++tot] = x;
    inorder(tr[x].r);
}
void build(int& x, int l, int r) {
    int mid = (l + r) >> 1;
    x = order[mid];
    if (l == r) {
        initnode(x);
        return;
    }
    if (l < mid) build(tr[x].l, l, mid - 1);
    if (l == mid) tr[x].l = 0;
    build(tr[x].r, mid + 1, r);
    pushup(x);
}
void rebuild(int& x) {
    cnt = 0;
    inorder(x);
    if (cnt) build(x, 1, cnt);
    else x = 0;
}
int rnk(int x, int k) {
    if (!x) return 0;
    if (k > tr[x].key) return tr[tr[x].l].siz + tr[x].del + rnk(tr[x].r, k);
    else return rnk(tr[x].l, k);
}
int kth(int k) {
    int x = root;
    while (x) {
        if (tr[x].del && tr[tr[x].l].siz + 1 == k) return tr[x].key;
        else if (tr[tr[x].l].siz >= k) x = tr[x].l;
        else {
            k -= tr[tr[x].l].siz + tr[x].del;
            x = tr[x].r;
        }
    }
    return tr[x].key;
}
void insert(int& x, int k) {
    if (!x) {
        x = st[tot--];
        tr[x].key = k;
        initnode(x);
        return;
    }
    tr[x].siz++;
    tr[x].tot++;
    if (tr[x].key >= k) insert(tr[x].l, k);
    else insert(tr[x].r, k);
    if (notbalance(x)) rebuild(x);
}
void removek(int& x, int k) {
    tr[x].siz--;
    if (tr[x].del && tr[tr[x].l].siz + 1 == k) {
        tr[x].del = 0;
        return;
    }
    if (tr[tr[x].l].siz + tr[x].del >= k) removek(tr[x].l, k);
    else removek(tr[x].r, k - tr[tr[x].l].siz - tr[x].del);
}
void remove(int k) {
    removek(root, rnk(root, k) + 1);
    if (tr[root].tot * alpha >= tr[root].siz) rebuild(root);
}
void solve() {
    for (int i = N - 1; i >= 1; --i) st[++tot] = i;
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        int op, x;
        cin >> op >> x;
        if (op == 1) insert(root, x);
        else if (op == 2) remove(x);
        else if (op == 3) cout << rnk(root, x) + 1 << '\n';
        else if (op == 4) cout << kth(x) << '\n';
        else if (op == 5) cout << kth(rnk(root, x)) << '\n';
        else cout << kth(rnk(root, x + 1) + 1) << '\n';
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. Treap

P3369 【模板】普通平衡树

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
#define P pair
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e9;
const ll N = 1e5 + 10;
struct node {
    int l, r, key, val, cnt, siz;
}tr[N];
int root, tot = 0;
int creatnode(int k) {
    tr[++tot].key = k;
    tr[tot].val = rand();
    tr[tot].cnt = tr[tot].siz = 1;
    return tot;
}
void pushup(int x) {
    tr[x].siz = tr[tr[x].l].siz + tr[tr[x].r].siz + tr[x].cnt;
}
void build() {
    creatnode(-INF), creatnode(INF);
    root = 1;
    tr[1].r = 2;
    pushup(root);
}
void zig(int& x) {
    int p = tr[x].l;
    tr[x].l = tr[p].r, tr[p].r = x, x = p;
    pushup(tr[x].r), pushup(x);
}
void zag(int& x) {
    int p = tr[x].r;
    tr[x].r = tr[p].l, tr[p].l = x, x = p;
    pushup(tr[x].l), pushup(x);
}
void insert(int& x, int k) {
    if (!x) x = creatnode(k);
    else if (k == tr[x].key) tr[x].cnt++;
    else if (k < tr[x].key) {
        insert(tr[x].l, k);
        if (tr[tr[x].l].val > tr[x].val) zig(x);
    }
    else {
        insert(tr[x].r, k);
        if (tr[tr[x].r].val > tr[x].val) zag(x);
    }
    pushup(x);
}
void remove(int& x, int k) {
    if (!x) return;
    if (k == tr[x].key) {
        if (tr[x].cnt > 1) tr[x].cnt--;
        else if (tr[x].l || tr[x].r) {
            if (!tr[x].r || tr[tr[x].l].val > tr[tr[x].r].val) {
                zig(x);
                remove(tr[x].r, k);
            }
            else {
                zag(x);
                remove(tr[x].l, k);
            }
        }
        else x = 0;
    }
    else if (k < tr[x].key) remove(tr[x].l, k);
    else remove(tr[x].r, k);
    pushup(x);
}
int query1(int x, int k) {
    if (!x) return 0;
    if (k == tr[x].key) return tr[tr[x].l].siz + 1;
    else if (k < tr[x].key) return query1(tr[x].l, k);
    else return tr[tr[x].l].siz + tr[x].cnt + query1(tr[x].r, k);
}
int query2(int x, int k) {
    if (!x) return INF;
    if (k <= tr[tr[x].l].siz) return query2(tr[x].l, k);
    else if (k <= tr[tr[x].l].siz + tr[x].cnt) return tr[x].key;
    else return query2(tr[x].r, k - tr[tr[x].l].siz - tr[x].cnt);
}
int pre(int x, int k) {
    if (!x) return -INF;
    if (k <= tr[x].key) return pre(tr[x].l, k);
    else return max(tr[x].key, pre(tr[x].r, k));
}
int nxt(int x, int k) {
    if (!x) return INF;
    if (k >= tr[x].key) return nxt(tr[x].r, k);
    else return min(tr[x].key, nxt(tr[x].l, k));
}
void solve() {
    build();
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        int op, x;
        cin >> op >> x;
        if (op == 1) insert(root, x);
        else if (op == 2) remove(root, x);
        else if (op == 3) cout << query1(root, x) - 1 << '\n';
        else if (op == 4) cout << query2(root, x + 1) << '\n';
        else if (op == 5) cout << pre(root, x) << '\n';
        else cout << nxt(root, x) << '\n';
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. FHQ Treap

P3369 【模板】普通平衡树

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
#define P pair
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 1e5 + 10;
struct node {
    int l, r, key, val, siz;
}tr[N];
int root=0, tot = 0;
void creatnode(int k) {
    tr[++tot].key = k;
    tr[tot].val = rand();
    tr[tot].siz = 1;
}
void pushup(int x) {
    tr[x].siz = tr[tr[x].l].siz + tr[tr[x].r].siz + 1;
}
void split(int x, int& l, int& r,int k) {
    if (!x) {
        l = r = 0;
        return;
    }
    if (tr[x].key <= k) {
        l = x;
        split(tr[x].r, tr[x].r, r, k);
    }
    else {
        r = x;
        split(tr[x].l, l, tr[x].l, k);
    }
    pushup(x);
}
int merge(int x, int y) {
    if (!x || !y) return x + y;
    if (tr[x].val >= tr[y].val) {
        tr[x].r = merge(tr[x].r, y);
        pushup(x);
        return x;
    }
    else {
        tr[y].l = merge(x, tr[y].l);
        pushup(y);
        return y;
    }
}
void insert(int k) {
    int l, r;
    split(root, l, r, k);
    creatnode(k);
    int p = merge(l, tot);
    root = merge(p, r);
}
void remove(int k) {
    int l, r, p;
    split(root, l, r, k);
    split(l, l, p, k-1);
    p = merge(tr[p].l, tr[p].r);
    root = merge(merge(l, p), r);
}
void rnk(int k) {
    int l, r;
    split(root, l, r, k - 1);
    cout << tr[l].siz + 1 << '\n';
    root = merge(l, r);
}
int kth(int x,int k) {
    if (k == tr[tr[x].l].siz + 1) return tr[x].key;
    else if (k <= tr[tr[x].l].siz) return kth(tr[x].l, k);
    else return kth(tr[x].r, k - tr[tr[x].l].siz - 1);
}
void pre(int k) {
    int l, r;
    split(root, l, r, k - 1);
    cout<> n;
    for (int i = 1; i <= n; ++i) {
        int op, x;
        cin >> op >> x;
        if (op == 1) insert(x);
        else if (op == 2) remove(x);
        else if (op == 3) rnk(x);
        else if (op == 4) cout << kth(root,x) << '\n';
        else if (op == 5) pre(x);
        else nxt(x);
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
排名分裂P4008 [NOI2003] 文本编辑器
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
#define P pair
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 3e6 + 10;
struct node {
    int l, r, val, siz;
    char key;
}tr[N];
int root = 0, tot = 0,pos=0;
void creatnode(char k) {
    tr[++tot].key = k;
    tr[tot].val = rand();
    tr[tot].siz = 1;
}
void pushup(int x) {
    tr[x].siz = tr[tr[x].l].siz + tr[tr[x].r].siz + 1;
}
void split(int x, int& l, int& r, int k) {
    if (!x) {
        l = r = 0;
        return;
    }
    if (tr[tr[x].l].siz+1 <= k) {
        l = x;
        split(tr[x].r, tr[x].r, r, k - tr[tr[x].l].siz - 1);
    }
    else {
        r = x;
        split(tr[x].l, l, tr[x].l, k);
    }
    pushup(x);
}
int merge(int x, int y) {
    if (!x || !y) return x + y;
    if (tr[x].val >= tr[y].val) {
        tr[x].r = merge(tr[x].r, y);
        pushup(x);
        return x;
    }
    else {
        tr[y].l = merge(x, tr[y].l);
        pushup(y);
        return y;
    }
}
void insert(int len) {
    int l, r;
    split(root, l, r, pos);
    for (int i = 1; i <= len; ++i) {
        char ch = getchar();
        while (ch < 32 || ch>126) ch = getchar();
        creatnode(ch);
        l = merge(l, tot);
    }
    root = merge(l, r);
}
void remove(int len) {
    int l, r, p;
    split(root, l, r, pos+len);
    split(l, l, p, pos);
    root = merge(l, r);
}
void inorder(int x) {
    if (!x) return;
    inorder(tr[x].l);
    cout << tr[x].key;
    inorder(tr[x].r);
}
void get(int len) {
    int l, r,p;
    split(root, l, r, pos+len);
    split(l, l, p, pos);
    inorder(p);
    root = merge(merge(l, p), r);
}
void solve() {
    srand(time(0));
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        string op;
        int len;
        cin >> op;
        if (op[0] == 'M') cin >> pos;
        else if (op[0] == 'I') {
            cin >> len;
            insert(len);
        }
        else if (op[0] == 'D') {
            cin >> len;
            remove(len);
        }
        else if (op[0] == 'G') {
            cin >> len;
            get(len);
            cout << '\n';
        }
        else if (op[0] == 'P') pos--;
        else pos++;
    }
}
int main() {
    //ios::sync_with_stdio(false);
    //cin.tie(0);
    //cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
P3391 【模板】文艺平衡树
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
#define P pair
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 1e5 + 10;
struct node {
    int l, r, key, val, siz, tag;
}tr[N];
int root = 0, tot = 0;
void creatnode(int k) {
    tr[++tot].key = k;
    tr[tot].val = rand();
    tr[tot].siz = 1;
}
void pushup(int x) {
    tr[x].siz = tr[tr[x].l].siz + tr[tr[x].r].siz + 1;
}
void pushdown(int x) {
    if (tr[x].tag) {
        swap(tr[x].l, tr[x].r);
        tr[tr[x].l].tag ^= 1;
        tr[tr[x].r].tag ^= 1;
        tr[x].tag = 0;
    }
}
void split(int x, int& l, int& r, int k) {
    if (!x) {
        l = r = 0;
        return;
    }
    pushdown(x);
    if (tr[tr[x].l].siz + 1 <= k) {
        l = x;
        split(tr[x].r, tr[x].r, r, k - tr[tr[x].l].siz - 1);
    }
    else {
        r = x;
        split(tr[x].l, l, tr[x].l, k);
    }
    pushup(x);
}
int merge(int x, int y) {
    if (!x || !y) return x + y;
    if (tr[x].val >= tr[y].val) {
        pushdown(x);
        tr[x].r = merge(tr[x].r, y);
        pushup(x);
        return x;

    }
    else {
        pushdown(y);
        tr[y].l = merge(x, tr[y].l);
        pushup(y);
        return y;
    }
}
void inorder(int x) {
    if (!x) return;
    pushdown(x);
    inorder(tr[x].l);
    cout << tr[x].key << " ";
    inorder(tr[x].r);
}
void solve() {
    srand(time(0));
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) {
        creatnode(i);
        root = merge(root, tot);
    }
    for (int i = 1; i <= m; ++i) {
        int l, r, p, x, y;
        cin >> x >> y;
        split(root, l, r, y);
        split(l, l, p, x - 1);
        tr[p].tag ^= 1;
        root = merge(merge(l, p), r);
    }
    inorder(root);
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
P3835 【模板】可持久化平衡树
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
#define P pair
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 2 << 30 - 1;
const ll N = 5e5 + 10;
struct node {
    int l, r, key, val, siz;
}tr[N << 7];
int root[N], tot = 0, idx = 0;
void creatnode(int k) {
    tr[++tot].key = k;
    tr[tot].val = rand();
    tr[tot].siz = 1;
}
void pushup(int x) {
    tr[x].siz = tr[tr[x].l].siz + tr[tr[x].r].siz + 1;
}
int clone(int x) {
    ++tot;
    tr[tot] = tr[x];
    return tot;
}
void split(int x, int& l, int& r, int k) {
    if (!x) {
        l = r = 0;
        return;
    }
    if (tr[x].key <= k) {
        l = clone(x);
        split(tr[l].r, tr[l].r, r, k);
        pushup(l);
    }
    else {
        r = clone(x);
        split(tr[r].l, l, tr[r].l, k);
        pushup(r);
    }
}
int merge(int x, int y) {
    if (!x || !y) return x + y;
    if (tr[x].val >= tr[y].val) {
        tr[x].r = merge(tr[x].r, y);
        pushup(x);
        return x;
    }
    else {
        tr[y].l = merge(x, tr[y].l);
        pushup(y);
        return y;
    }
}
int kth(int x, int k) {
    if (k <= tr[tr[x].l].siz) return kth(tr[x].l, k);
    else if (k == tr[tr[x].l].siz + 1) return tr[x].key;
    else return kth(tr[x].r, k - tr[tr[x].l].siz - 1);
}
void solve() {
    srand(time(0));
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        int v, op, x, l, r, p;
        cin >> v >> op >> x;
        if (op == 1) {
            split(root[v], l, r, x);
            creatnode(x);
            root[++idx] = merge(merge(l, tot), r);
        }
        else if (op == 2) {
            split(root[v], l, r, x);
            split(l, l, p, x - 1);
            p = merge(tr[p].l, tr[p].r);
            root[++idx] = merge(merge(l, p), r);
        }
        else if (op == 3) {
            split(root[v], l, r, x - 1);
            cout << tr[l].siz + 1 << '\n';
            root[++idx] = merge(l, r);
        }
        else if (op == 4) {
            cout << kth(root[v], x) << '\n';
            root[++idx] = root[v];
        }
        else if (op == 5) {
            split(root[v], l, r, x - 1);
            if (!l) cout << -INF << '\n';
            else cout << kth(l, tr[l].siz) << '\n';
            root[++idx] = merge(l, r);
        }
        else {
            split(root[v], l, r, x);
            if (!r) cout << INF << '\n';
            else cout << kth(r, 1) << '\n';
            root[++idx] = merge(l, r);
        }
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
P5055 【模板】可持久化文艺平衡树
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
#define P pair
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 2e5 + 10;
struct node {
    ll l, r, key, val, sum, siz, tag;
}tr[N << 7];
ll root[N], tot = 0, idx = 0;
void creatnode(ll k) {
    ++tot;
    tr[tot].key = tr[tot].sum = k;
    tr[tot].val = rand();
    tr[tot].siz = 1;
}
ll clone(ll x) {
    ++tot;
    tr[tot] = tr[x];
    return tot;
}
void pushup(ll x) {
    tr[x].siz = tr[tr[x].l].siz + tr[tr[x].r].siz + 1;
    tr[x].sum = tr[tr[x].l].sum + tr[tr[x].r].sum + tr[x].key;
}
void pushdown(ll x) {
    if (tr[x].tag) {
        if (tr[x].l) tr[x].l = clone(tr[x].l);
        if (tr[x].r) tr[x].r = clone(tr[x].r);
        swap(tr[x].l, tr[x].r);
        tr[tr[x].l].tag ^= 1, tr[tr[x].r].tag ^= 1;
        tr[x].tag = 0;
    }
}
void split(ll x, ll& l, ll& r, ll k) {
    if (!x) {
        l = r = 0;
        return;
    }
    pushdown(x);
    if (tr[tr[x].l].siz + 1 <= k) {
        l = clone(x);
        split(tr[l].r, tr[l].r, r, k - tr[tr[x].l].siz - 1);
        pushup(l);
    }
    else {
        r = clone(x);
        split(tr[r].l, l, tr[r].l, k);
        pushup(r);
    }
}
ll merge(ll x, ll y) {
    if (!x || !y) return x + y;
    if (tr[x].val >= tr[y].val) {
        pushdown(x);
        tr[x].r = merge(tr[x].r, y);
        pushup(x);
        return x;
    }
    else {
        pushdown(y);
        tr[y].l = merge(x, tr[y].l);
        pushup(y);
        return y;
    }
}
void solve() {
    srand(time(0));
    ll n, last = 0;
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        ll v, op;
        cin >> v >> op;
        if (op == 1) {
            ll p, x, L, R;
            cin >> p >> x;
            p ^= last, x ^= last;
            split(root[v], L, R, p);
            creatnode(x);
            root[++idx] = merge(merge(L, tot), R);
        }
        else if (op == 2) {
            ll p, L, R, tmp;
            cin >> p;
            p ^= last;
            split(root[v], L, R, p);
            split(L, L, tmp, p - 1);
            root[++idx] = merge(L, R);
        }
        else if (op == 3) {
            ll l, r, L, R, tmp;
            cin >> l >> r;
            l ^= last, r ^= last;
            split(root[v], L, R, r);
            split(L, L, tmp, l - 1);
            tr[tmp].tag ^= 1;
            root[++idx] = merge(merge(L, tmp), R);
        }
        else {
            ll l, r, L, R, tmp;
            cin >> l >> r;
            l ^= last, r ^= last;
            split(root[v], L, R, r);
            split(L, L, tmp, l - 1);
            last = tr[tmp].sum;
            cout << last << '\n';
            root[++idx] = merge(merge(L, tmp), R);
        }
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. Splay

P4008 [NOI2003] 文本编辑器
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
#define P pair
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 4e6 + 10;
struct node {
    char key;
    int l, r, fa, siz;
}tr[N];
int root = 1, tot = 2;
char s[N];
void init() {
    tr[1].siz = 2, tr[1].l = 2;
    tr[2].siz = 1, tr[2].fa = 1;
}
void pushup(int x) {
    tr[x].siz = tr[tr[x].l].siz + tr[tr[x].r].siz + 1;
}
void rotate(int x) {
    int y = tr[x].fa, z = tr[y].fa;
    int k = (x == tr[y].r);
    if (k == 1) {
        tr[y].r = tr[x].l;
        tr[tr[x].l].fa = y;
        tr[x].l = y;
    }
    else {
        tr[y].l = tr[x].r;
        tr[tr[x].r].fa = y;
        tr[x].r = y;
    }
    tr[y].fa = x;
    tr[x].fa = z;
    if (z) {
        if (tr[z].l == y) tr[z].l = x;
        else tr[z].r = x;
    }
    pushup(y), pushup(x);
}
void splay(int x, int k) {
    while (tr[x].fa != k) {
        int y = tr[x].fa, z = tr[y].fa;
        if (z != k) {
            if ((x == tr[y].r) == (y == tr[z].r)) rotate(y);
            else rotate(x);
        }
        rotate(x);
    }
    if (k == 0) root = x;
}
int build(int l,int r,int f) {
    if (l > r) return 0;
    int mid = (l + r) >> 1;
    int cur = ++tot;
    tr[cur].fa = f;
    tr[cur].key = s[mid];
    tr[cur].l = build(l, mid - 1, cur);
    tr[cur].r = build(mid + 1, r, cur);
    pushup(cur);
    return cur;
}
int kth(int x, int k) {
    if (k <= tr[tr[x].l].siz) return kth(tr[x].l, k);
    else if (k == tr[tr[x].l].siz + 1) return x;
    else return kth(tr[x].r, k - tr[tr[x].l].siz - 1);
}
void insert(int pos, int len) {
    int l = kth(root, pos), r = kth(root, pos + 1);
    splay(l, 0), splay(r, l);
    tr[r].l = build(1,len,r);
    pushup(r), pushup(l);
}
void remove(int x, int len) {
    int l = kth(root, x), r = kth(root, x + len + 1);
    splay(l, 0), splay(r, l);
    tr[r].l = 0;
    pushup(r), pushup(l);
}
void inorder(int x) {
    if (!x) return;
    inorder(tr[x].l);
    cout << tr[x].key;
    inorder(tr[x].r);
}
void solve() {
    int n,len,pos=1;
    cin >> n;
    init();
    for (int i = 1; i <= n; ++i) {
        string op;
        cin >> op;
        if (op[0] == 'M') cin >> pos,pos++;
        else if (op[0] == 'I') {
            cin >> len;
            for (int i = 1; i <= len; ++i) {
                char ch = getchar();
                while (ch < 32 || ch>126) ch = getchar();
                s[i] = ch;
            }
            insert(pos, len);
        }
        else if (op[0] == 'D') {
            cin >> len;
            remove(pos, len);
        }
        else if (op[0] == 'G') {
            cin >> len;
            int l = kth(root, pos), r = kth(root, pos+len+1);
            splay(l, 0), splay(r, l);
            inorder(tr[r].l);
            cout << '\n';
        }
        else if (op[0] == 'P') pos--;
        else pos++;
    }
}
int main() {
    //ios::sync_with_stdio(false);
    //cin.tie(0);
    //cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
P3391 【模板】文艺平衡树
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
#define P pair
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 1e5 + 10;
struct node {
    int l, r,fa, key, siz, tag;
}tr[N];
int root = 0, tot = 0,n,m;
void creatnode(int k,int p) {
    tr[++tot].key = k;
    tr[tot].fa = p;
    tr[tot].siz = 1;
}
void pushup(int x) {
    tr[x].siz = tr[tr[x].l].siz + tr[tr[x].r].siz + 1;
}
void pushdown(int x) {
    if (tr[x].tag) {
        swap(tr[x].l, tr[x].r);
        tr[tr[x].l].tag ^= 1;
        tr[tr[x].r].tag ^= 1;
        tr[x].tag = 0;
    }
}
void rotate(int x) {
    int y = tr[x].fa, z = tr[y]. fa;
    int k = (tr[y].r == x);
    if (k == 1) {
        tr[y].r = tr[x].l;
        tr[tr[x].l].fa = y;
        tr[x].l = y;
    }
    else {
        tr[y].l = tr[x].r;
        tr[tr[x].r].fa = y;
        tr[x].r = y;
    }
    tr[y].fa = x;
    tr[x].fa = z;
    if (tr[z].l == y) tr[z].l = x;
    else tr[z].r = x;
    pushup(y), pushup(x);
}
void splay(int x, int k) {
    while (tr[x].fa != k) {
        int y = tr[x].fa, z = tr[y].fa;
        if (z != k) {
            if ((tr[y].r == x) == (tr[z].r == y)) rotate(y);
            else rotate(x);
        }
        rotate(x);
    }
    if (k == 0) root = x;
}
void insert(int k) {
    int x = root, p = 0;
    while (x) {
        p = x;
        if (tr[x].key < k) x = tr[x].r;
        else x = tr[x].l;
    }
    creatnode(k,p);
    if (p) {
        if (k > tr[p].key) tr[p].r = tot;
        else tr[p].l = tot;
    }
    splay(tot, 0);
}
int kth(int x,int k) {
    pushdown(x);
    if (k <= tr[tr[x].l].siz) return kth(tr[x].l, k);
    else if (k == tr[tr[x].l].siz + 1) return x;
    else return kth(tr[x].r, k - tr[tr[x].l].siz - 1);
}
void inorder(int x) {
    if (!x) return;
    pushdown(x);
    inorder(tr[x].l);
    if (tr[x].key >= 1 && tr[x].key <= n) cout << tr[x].key << " ";
    inorder(tr[x].r);
}
void solve() {
    cin >> n >> m;
    for (int i = 0; i <= n + 1; ++i) insert(i);
    for (int i = 1; i <= m; ++i) {
        int l, r;
        cin >> l >> r;
        l = kth(root,l), r = kth(root,r + 2);
        splay(l, 0), splay(r, l);
        tr[tr[r].l].tag ^= 1;
    }
    inorder(root);
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 笛卡尔树

P5854 【模板】笛卡尔树

建树

RMQ为区间端点LCA的值

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
#define P pair
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e9;
const ll N = 1e7 + 10;
struct node {
    int l, r, val, fa;
}tr[N];
int read() {
    int res = 0;
    char ch = getchar();
    while (ch < '0' || ch>'9') ch = getchar();
    while (ch >= '0' && ch <= '9') { res = (res << 3) + (res << 1) + (ch ^ 48); ch = getchar(); }
    return res;
}
void build(int n) {
    for (int i = 1; i <= n; ++i) {
        int p = i - 1;
        while (tr[p].val > tr[i].val) p = tr[p].fa;
        tr[i].l = tr[p].r;
        tr[tr[p].r].fa = i;
        tr[p].r = i;
        tr[i].fa = p;
    }
}
void solve() {
    ll n, ans1 = 0, ans2 = 0;
    n=read();
    for (int i = 1; i <= n; ++i) tr[i].val=read();
    tr[0].val = -INF;
    build(n);
    for (int i = 1; i <= n; ++i) {
        ans1 ^= 1ll*i * (tr[i].l + 1);
        ans2 ^= 1ll*i * (tr[i].r + 1);
    }
    cout << ans1 << " " << ans2;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 线段树套平衡树

P3380 【模板】二逼平衡树(树套树)

排名为k的值

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
#define P pair
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 2147483647;
const ll N = 2e6 + 10;
struct tree {
    int l, r, siz, key, val;
}tr[N];
int a[N], root[N], tot = 0;
inline int read() {
    int res = 0;
    char ch = getchar();
    while (ch < '0' || ch>'9') ch = getchar();
    while (ch >= '0' && ch <= '9') { res = (res << 3) + (res << 1) + (ch ^ 48); ch = getchar(); }
    return res;
}
inline void pushup(int x) {
    tr[x].siz = tr[tr[x].l].siz + tr[tr[x].r].siz + 1;
}
inline void creatnode(int k) {
    tr[++tot].key = k;
    tr[tot].val = rand();
    tr[tot].siz = 1;
}
inline void split(int x, int& l, int& r, int k) {
    if (!x) {
        l = r = 0;
        return;
    }
    if (tr[x].key <= k) {
        l = x;
        split(tr[x].r, tr[x].r, r, k);
    }
    else {
        r = x;
        split(tr[x].l, l, tr[x].l, k);
    }
    pushup(x);
}
inline int merge(int x, int y) {
    if (!x || !y) return x + y;
    if (tr[x].val >= tr[y].val) {
        tr[x].r = merge(tr[x].r, y);
        pushup(x);
        return x;
    }
    else {
        tr[y].l = merge(x, tr[y].l);
        pushup(y);
        return y;
    }
}
inline void insert(int& rt, int k) {
    int l, r;
    split(rt, l, r, k);
    creatnode(k);
    rt = merge(merge(l, tot), r);
}
inline void remove(int& rt, int k) {
    int l, r, p;
    split(rt, l, r, k);
    split(l, l, p, k - 1);
    p = merge(tr[p].l, tr[p].r);
    rt = merge(merge(l, p), r);
}
inline int rnk(int& rt, int k) {
    int u = rt, res = 0;
    while (u) {
        if (tr[u].key < k) res += tr[tr[u].l].siz + 1, u = tr[u].r;
        else u = tr[u].l;
    }
    return res;
}
inline int kth(int x, int k) {
    if (k == tr[tr[x].l].siz + 1) return tr[x].key;
    else if (k <= tr[tr[x].l].siz) return kth(tr[x].l, k);
    else return kth(tr[x].r, k - tr[tr[x].l].siz - 1);
}
inline int pre(int& rt, int k) {
    int l, r;
    split(rt, l, r, k - 1);
    int res = kth(l, tr[l].siz);
    rt = merge(l, r);
    return res;
}
inline int nxt(int& rt, int k) {
    int l, r;
    split(rt, l, r, k);
    int res = kth(r, 1);
    rt = merge(l, r);
    return res;
}
inline void build(int x, int l, int r) {
    insert(root[x], -INF), insert(root[x], INF);
    for (register int i = l; i <= r; ++i) insert(root[x], a[i]);
    int mid = l + r >> 1;
    if (l == r) return;
    build(x << 1, l, mid);
    build(x << 1 | 1, mid + 1, r);
}
inline void modify(int x, int l, int r, int p, int k) {
    remove(root[x], a[p]);
    insert(root[x], k);
    if (l == r) return;
    int mid = l + r >> 1;
    if (p <= mid) modify(x << 1, l, mid, p, k);
    else modify(x << 1 | 1, mid + 1, r, p, k);
}
inline int query(int x, int l, int r, int ql, int qr, int k) {
    if (ql <= l && qr >= r) return rnk(root[x], k) - 1;
    int res = 0;
    int mid = l + r >> 1;
    if (ql <= mid) res += query(x << 1, l, mid, ql, qr, k);
    if (qr > mid) res += query(x << 1 | 1, mid + 1, r, ql, qr, k);
    return res;
}
inline int querypre(int x, int l, int r, int ql, int qr, int k) {
    if (ql <= l && qr >= r) return pre(root[x], k);
    int res = -INF;
    int mid = l + r >> 1;
    if (ql <= mid) res = max(res, querypre(x << 1, l, mid, ql, qr, k));
    if (qr > mid) res = max(res, querypre(x << 1 | 1, mid + 1, r, ql, qr, k));
    return res;
}
inline int querynxt(int x, int l, int r, int ql, int qr, int k) {
    if (ql <= l && qr >= r) return nxt(root[x], k);
    int res = INF;
    int mid = l + r >> 1;
    if (ql <= mid) res = min(res, querynxt(x << 1, l, mid, ql, qr, k));
    if (qr > mid) res = min(res, querynxt(x << 1 | 1, mid + 1, r, ql, qr, k));
    return res;
}
inline void solve() {
    srand(time(0));
    int n, m;
    n = read(), m = read();
    for (register int i = 1; i <= n; ++i) a[i] = read();
    build(1, 1, n);
    for (int i = 1; i <= m; ++i) {
        int op, k;
        op = read();
        if (op == 1) {
            int l, r;
            l = read(), r = read(), k = read();
            cout << query(1, 1, n, l, r, k) + 1 << '\n';
        }
        else if (op == 2) {
            int l, r;
            l = read(), r = read(), k = read();
            int L = 1, R = 1e8;
            while (L <= R) {
                int mid = L + R >> 1;
                if (query(1, 1, n, l, r, mid) + 1 <= k) L = mid + 1;
                else R = mid - 1;
            }
            cout << R << '\n';
        }
        else if (op == 3) {
            int pos;
            pos = read(), k = read();
            modify(1, 1, n, pos, k);
            a[pos] = k;
        }
        else if (op == 4) {
            int l, r;
            l = read(), r = read(), k = read();
            cout << querypre(1, 1, n, l, r, k) << '\n';
        }
        else {
            int l, r;
            l = read(), r = read(), k = read();
            cout << querynxt(1, 1, n, l, r, k) << '\n';
        }
    }
}
int main() {
    //ios::sync_with_stdio(false);
    //cin.tie(0);
    //cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. KD树

最近邻点hdu2966 In case of failure

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
#define P pair
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 1e5 + 10;
const int k = 2;
struct Point {
    ll dim[k];
}p[N], tr[N];
ll ans, cur;
bool cmp(Point a, Point b) {
    return a.dim[cur] < b.dim[cur];
}
ll sq(ll x) {
    return x * x;
}
ll dis(Point a, Point b) {
    return sq(a.dim[0] - b.dim[0]) + sq(a.dim[1] - b.dim[1]);
}
void build(int l, int r, int dep) {
    if (l >= r) return;
    int mid = l + r >> 1;
    cur = dep;
    nth_element(tr + l, tr + mid, tr + r, cmp);
    build(l, mid, (dep + 1) % k);
    build(mid + 1, r, (dep + 1) % k);
}
void query(int l, int r, int dep, Point a) {
    if (l >= r) return;
    int mid = l + r >> 1;
    ll d = dis(tr[mid], a);
    if (!ans || d && ans > d) ans = d;
    if (a.dim[dep] > tr[mid].dim[dep]) {
        query(mid + 1, r, (dep + 1) % k, a);
        if (ans > sq(a.dim[dep] - tr[mid].dim[dep]))
            query(l, mid, (dep + 1) % k, a);
    }
    else {
        query(l, mid, (dep + 1) % k, a);
        if (ans > sq(a.dim[dep] - tr[mid].dim[dep]))
            query(mid + 1, r, (dep + 1) % k, a);
    }
}
void solve() {
    int n;
    cin >> n;
    for (int i = 0; i < n; ++i) {
        cin >> p[i].dim[0] >> p[i].dim[1];
        tr[i] = p[i];
    }
    build(0, n, 0);
    for (int i = 0; i < n; ++i) {
        ans = 0;
        query(0, n, 0, p[i]);
        cout << ans << '\n';
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    //_t = 1;
    cin >> _t;
    while (_t--) {
        solve();
    }
    return 0;
}
区间查询P4148 简单题

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
#define P pair
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 2e5 + 10;
const double alpha = 0.75;
struct point {
    int dim[2], k;
    point() {}
    point(int x, int y, int key) {
        dim[0] = x;
        dim[1] = y;
        k = key;
    }
}order[N];
struct node {
    int l, r, sum, siz, mn[2], mx[2];
    point p;
}tr[N];
int root, tot, cur, top, st[N], cnt;
bool cmp(point a, point b) {
    return a.dim[cur] < b.dim[cur];
}
void pushup(int u) {
    for (int i = 0; i < 2; ++i) {
        tr[u].mn[i] = tr[u].mx[i] = tr[u].p.dim[i];
        if (tr[u].l) {
            tr[u].mn[i] = min(tr[u].mn[i], tr[tr[u].l].mn[i]);
            tr[u].mx[i] = max(tr[u].mx[i], tr[tr[u].l].mx[i]);
        }
        if (tr[u].r) {
            tr[u].mn[i] = min(tr[u].mn[i], tr[tr[u].r].mn[i]);
            tr[u].mx[i] = max(tr[u].mx[i], tr[tr[u].r].mx[i]);
        }
    }
    tr[u].sum = tr[tr[u].l].sum + tr[tr[u].r].sum + tr[u].p.k;
    tr[u].siz = tr[tr[u].l].siz + tr[tr[u].r].siz + 1;
}
void slap(int u) {
    if (!u) return;
    slap(tr[u].l);
    order[++cnt] = tr[u].p;
    st[++top] = u;
    slap(tr[u].r);
}
int build(int l, int r, int d) {
    if (l > r) return 0;
    int u;
    if (top) u = st[top--];
    else u = ++tot;
    int mid = l + r >> 1;
    cur = d;
    nth_element(order + l, order + mid, order + r + 1, cmp);
    tr[u].p = order[mid];
    tr[u].l = build(l, mid - 1, d ^ 1);
    tr[u].r = build(mid + 1, r, d ^ 1);
    pushup(u);
    return u;
}
bool notbalance(int u) {
    if (tr[tr[u].l].siz > alpha * tr[u].siz || tr[tr[u].r].siz > alpha * tr[u].siz) return 1;
    else return 0;
}
void insert(int& u, point x, int d) {
    if (!u) {
        if (top) u = st[top--];
        else u = ++tot;
        tr[u].l = tr[u].r = 0;
        tr[u].p = x;
        pushup(u);
        return;
    }
    if (x.dim[d] <= tr[u].p.dim[d]) insert(tr[u].l, x, d ^ 1);
    else insert(tr[u].r, x, d ^ 1);
    pushup(u);
    if (notbalance(u)) {
        cnt = 0;
        slap(u);
        u = build(1, tr[u].siz, d);
    }
}
int query(int u, int x1, int y1, int x2, int y2) {
    if (!u) return 0;
    int xx1 = tr[u].mn[0], yy1 = tr[u].mn[1], xx2 = tr[u].mx[0], yy2 = tr[u].mx[1];
    if (x1 <= xx1 && x2 >= xx2 && y1 <= yy1 && y2 >= yy2) return tr[u].sum;
    if (x1 > xx2 || x2yy2 || y2 < yy1) return 0;
    int ans = 0;
    xx1 = tr[u].p.dim[0], yy1 = tr[u].p.dim[1], xx2 = tr[u].p.dim[0], yy2 = tr[u].p.dim[1];
    if (x1 <= xx1 && x2 >= xx2 && y1 <= yy1 && y2 >= yy2) ans += tr[u].p.k;
    ans += query(tr[u].l, x1, y1, x2, y2) + query(tr[u].r, x1, y1, x2, y2);
    return ans;
}
void solve() {
    int n, ans = 0;
    cin >> n;
    while (1) {
        int op;
        cin >> op;
        if (op == 1) {
            int x, y, k;
            cin >> x >> y >> k;
            x ^= ans, y ^= ans, k ^= ans;
            insert(root, point(x, y, k), 0);
        }
        else if (op == 2) {
            int x1, y1, x2, y2;
            cin >> x1 >> y1 >> x2 >> y2;
            x1 ^= ans, y1 ^= ans, x2 ^= ans, y2 ^= ans;
            ans = query(root, x1, y1, x2, y2);
            cout << ans << '\n';
        }
        else break;
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
K近邻 P2093 [国家集训队]JZPFAR
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
#define P pair
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 1e5 + 10;
struct point {
    ll dim[2], id;
}p[N];
struct tree {
    ll l, r, mx[2], mn[2], id;
    point p;
}tr[N];
struct node {
    ll dis, id;
    bool operator<(const node a)const {
        return dis == a.dis ? id < a.id : dis > a.dis;
    }
};
priority_queue q;
int root, tot, now;
bool cmp(point a, point b) {
    return a.dim[now] < b.dim[now];
}
void pushup(int x) {
    for (int i = 0; i < 2; ++i) {
        tr[x].mn[i] = tr[x].mx[i] = tr[x].p.dim[i];
        if (tr[x].l) {
            tr[x].mn[i] = min(tr[x].mn[i], tr[tr[x].l].mn[i]);
            tr[x].mx[i] = max(tr[x].mx[i], tr[tr[x].l].mx[i]);
        }
        if (tr[x].r) {
            tr[x].mn[i] = min(tr[x].mn[i], tr[tr[x].r].mn[i]);
            tr[x].mx[i] = max(tr[x].mx[i], tr[tr[x].r].mx[i]);
        }
    }
}
int build(int l, int r, int d) {
    if (l > r) return 0;
    int x = ++tot;
    int mid = l + r >> 1;
    now = d;
    nth_element(p + l, p + mid, p + r + 1, cmp);
    tr[x].p = p[mid];
    tr[x].id = p[mid].id;
    tr[x].l = build(l, mid - 1, d ^ 1);
    tr[x].r = build(mid + 1, r, d ^ 1);
    pushup(x);
    return x;
}
ll sq(ll x) {
    return x * x;
}
ll dis(point a, point b) {
    return sq(a.dim[0] - b.dim[0]) + sq(a.dim[1] - b.dim[1]);
}
ll getdis(int x, point a) {
    ll res = 0;
    for (int i = 0; i < 2; ++i) {
        res += max(sq(a.dim[i] - tr[x].mx[i]), sq(a.dim[i] - tr[x].mn[i]));
    }
    return res;
}
void query(int x, point a) {
    if (!x) return;
    ll res = dis(tr[x].p, a);
    if (res > q.top().dis || res == q.top().dis && tr[x].id < q.top().id) {
        q.pop();
        q.push({ res,tr[x].id });
    }
    ll ld = INF, rd = INF;
    if (tr[x].l) ld = getdis(tr[x].l, a);
    if (tr[x].r) rd = getdis(tr[x].r, a);
    if (ld < rd) {
        if (rd >= q.top().dis) query(tr[x].r, a);
        if (ld >= q.top().dis) query(tr[x].l, a);
    }
    else {
        if (ld > q.top().dis) query(tr[x].l, a);
        if (rd > q.top().dis) query(tr[x].r, a);
    }
}
void solve() {
    int n, m, k;
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        cin >> p[i].dim[0] >> p[i].dim[1];
        p[i].id = i;
    }
    root = build(1, n, 0);
    cin >> m;
    for (int i = 1; i <= m; ++i) {
        point a;
        cin >> a.dim[0] >> a.dim[1] >> k;
        while (!q.empty()) q.pop();
        for (int j = 1; j <= k; ++j) q.push({ -1,0 });
        query(root, a);
        cout << q.top().id << '\n';
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin >> _t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. LCT

P3690 【模板】动态树(Link Cut Tree)

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
#define P pair
const double eps = 1e-8;
const ll mod = 998244353;
const ll INF = 1e18;
const ll N = 1e5 + 10;
struct node {
    int l, r,fa, key, tag, sum;
}tr[N];
int st[N];
void pushup(int x) {
    tr[x].sum = tr[tr[x].l].sum ^ tr[tr[x].r].sum ^ tr[x].key;
}
void pushtag(int x) {
    swap(tr[x].l, tr[x].r);
    tr[x].tag ^= 1;
}
void pushdown(int x) {
    if (tr[x].tag) {
        pushtag(tr[x].l);
        pushtag(tr[x].r);
        tr[x].tag = 0;
    }
}
bool isroot(int x) {
    return tr[tr[x].fa].l != x && tr[tr[x].fa].r != x;
}
void rotate(int x) {
    int y = tr[x].fa, z = tr[y].fa;
    int k = (x == tr[y].r);
    if (!isroot(y)) {
        if (tr[z].l == y) tr[z].l = x;
        else tr[z].r = x;
    }
    if (k == 1) {
        tr[y].r = tr[x].l;
        tr[tr[x].l].fa = y;
        tr[x].l = y;
    }
    else {
        tr[y].l = tr[x].r;
        tr[tr[x].r].fa = y;
        tr[x].r = y;
    }
    tr[y].fa = x;
    tr[x].fa = z;
    pushup(y), pushup(x);
}
void splay(int x) {
    int top = 0, p = x;
    st[++top] = p;
    while (!isroot(p)) st[++top] = p = tr[p].fa;
    while (top) pushdown(st[top--]);
    while (!isroot(x)) {
        int y = tr[x].fa, z = tr[y].fa;
        if (!isroot(y)) {
            if ((tr[y].r == x) == (tr[z].r == y)) rotate(y);
            else rotate(x);
        }
        rotate(x);
    }
}
void access(int x) {
    int z = x;
    for (int y = 0; x; y = x, x = tr[x].fa){
        splay(x);
        tr[x].r = y;
        pushup(x);
    }
    splay(z);
}
void makeroot(int x) {
    access(x);
    pushtag(x);
}
int findroot(int x) {
    access(x);
    while (tr[x].l) x = tr[x].l;
    splay(x);
    return x;
}
void split(int x, int y) {
    makeroot(x);
    access(y);
}
void link(int x, int y) {
    makeroot(x);
    if (findroot(y) != x) tr[x].fa = y;
}
void cut(int x, int y) {
    makeroot(x);
    if (findroot(y) == x && tr[y].fa == x && !tr[y].l) {
        tr[x].r = tr[y].fa = 0;
        pushup(x);
    }
}
void solve() {
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) cin >> tr[i].key;
    for (int i = 1; i <= m; ++i) {
        int op, x, y;
        cin >> op >> x >> y;
        if (op == 0) {
            split(x, y);
            cout << tr[y].sum << '\n';
        }
        else if (op == 1) link(x, y);
        else if (op == 2) cut(x, y);
        else {
            splay(x);
            tr[x].key = y;
            pushup(x);
        }
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin >> _t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 左偏树

P3377 【模板】左偏树(可并堆)

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
#define P pair
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 1e5 + 10;
struct {
    int l, r, key, dis;
    bool del;
}tr[N];
int f[N];
bool cmp(int x, int y) {
    if (tr[x].key != tr[y].key) return tr[x].key < tr[y].key;
    else return x < y;
}
int find(int x) {
    if (f[x] == x) return x;
    else return f[x] = find(f[x]);
}
int merge(int x, int y) {
    if (!x || !y) return x + y;
    if (!cmp(x, y)) swap(x, y);
    tr[x].r = merge(tr[x].r, y);
    if (tr[tr[x].l].dis < tr[tr[x].r].dis) swap(tr[x].l, tr[x].r);
    tr[x].dis = tr[tr[x].r].dis + 1;
    return x;
}
void solve() {
    int n, m;
    cin >> n >> m;
    tr[0].key = 2e9;
    for (int i = 1; i <= n; ++i) {
        cin >> tr[i].key;
        tr[i].dis = 1;
        f[i] = i;
    }
    for (int i = 1; i <= m; ++i) {
        int op;
        cin >> op;
        if (op == 1) {
            int x, y;
            cin >> x >> y;
            if (tr[x].del || tr[y].del) continue;
            x = find(x), y = find(y);
            if (x != y) {
                if (!cmp(x, y)) swap(x, y);
                merge(x, y);
                f[y] = x;
            }
        }
        else {
            int x;
            cin >> x;
            if (tr[x].del) {
                cout << -1 << '\n';
                continue;
            }
            x = find(x);
            cout << tr[x].key << '\n';
            if (!cmp(tr[x].l, tr[x].r)) swap(tr[x].l, tr[x].r);
            merge(tr[x].l, tr[x].r);
            tr[x].del = 1;
            f[x] = tr[x].l;
            f[tr[x].l] = tr[x].l;
        }
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. DLX(精确覆盖问题)

AcWing1067精确覆盖问题

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
#define P pair
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 6e3 + 10;
struct node {
    int l, r, u, d, row, col;
}p[N];
int n, m, cnt[N], tot, ans[N], top;
void init() {
    for (int i = 0; i <= m; ++i) {
        p[i].l = i - 1, p[i].r = i + 1;
        p[i].u = p[i].d = i;
    }
    p[0].l = m, p[m].r = 0;
    tot = m + 1;
}
void add(int& hh, int& tt, int x, int y) {
    p[tot].row = y, p[tot].col = x, cnt[x]++;
    p[tot].l = hh, p[tot].r = tt;
    p[hh].r = p[tt].l = tot;
    p[tot].u = x, p[tot].d = p[x].d;
    p[x].d = p[p[x].d].u = tot;
    tt = tot++;
}
void remove(int x) {
    p[p[x].l].r = p[x].r, p[p[x].r].l = p[x].l;
    for (int i = p[x].d; i != x; i = p[i].d) {
        for (int j = p[i].r; j != i; j = p[j].r) {
            cnt[p[j].col]--;
            p[p[j].d].u = p[j].u, p[p[j].u].d = p[j].d;
        }
    }
}
void resume(int x) {
    for (int i = p[x].u; i != x; i = p[i].u) {
        for (int j = p[i].l; j != i; j = p[j].l) {
            cnt[p[j].col]++;
            p[p[j].d].u = j, p[p[j].u].d = j;
        }
    }
    p[p[x].l].r = x, p[p[x].r].l = x;
}
bool dfs() {
    if (!p[0].r) return 1;
    int mn = p[0].r;
    for (int i = p[0].r; i; i = p[i].r) {
        if (cnt[i] < cnt[mn]) mn = i;
    }
    remove(mn);
    for (int i = p[mn].d; i != mn; i = p[i].d) {
        ans[++top] = p[i].row;
        for (int j = p[i].r; j != i; j = p[j].r) remove(p[j].col);
        if (dfs()) return 1;
        for (int j = p[i].l; j != i; j = p[j].l) resume(p[j].col);
        top--;
    }
    resume(mn);
    return 0;
}
void solve() {
    cin >> n >> m;
    init();
    for (int i = 1; i <= n; ++i) {
        int hh = tot, tt = tot;
        for (int j = 1; j <= m; ++j) {
            int x;
            cin >> x;
            if (x) add(hh, tt, j, i);
        }
    }
    if (dfs()) {
        for (int i = 1; i <= top; ++i) cout << ans[i] << " ";
    }
    else cout << "No Solution!";
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. DLX(重复覆盖问题)

AcWing2713重复覆盖问题

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
#define P pair
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 1e4 + 10;
struct node {
    int l, r, u, d, row, col;
}p[N];
int n, m, cnt[N], tot, ans[N], st[110];
inline void init() {
    for (register int i = 0; i <= m; ++i) {
        p[i].l = i - 1, p[i].r = i + 1;
        p[i].col = p[i].u = p[i].d = i;
    }
    p[0].l = m, p[m].r = 0;
    tot = m + 1;
}
inline void add(int& hh, int& tt, int x, int y) {
    p[tot].col = x, p[tot].row = y, cnt[x]++;
    p[tot].u = x, p[tot].d = p[x].d;
    p[x].d = p[p[x].d].u = tot;
    p[hh].r = p[tt].l = tot;
    p[tot].l = hh, p[tot].r = tt;
    tt = tot++;
}
inline int h() {
    int cnt = 0;
    for (register int i = 1; i <= m; ++i) st[i] = 0;
    for (register int i = p[0].r; i; i = p[i].r) {
        if (st[p[i].col]) continue;
        cnt++;
        st[p[i].col] = 1;
        for (register int j = p[i].d; j != i; j = p[j].d) {
            for (register int k = p[j].r; k != j; k = p[k].r) st[p[k].col] = 1;
        }
    }
    return cnt;
}
inline void remove(int x) {
    for (register int i = p[x].d; i != x; i = p[i].d) {
        p[p[i].l].r = p[i].r, p[p[i].r].l = p[i].l;
    }
}
inline void resume(int x) {
    for (register int i = p[x].u; i != x; i = p[i].u) {
        p[p[i].l].r = i, p[p[i].r].l = i;
    }
}
inline bool dfs(int k, int dep) {
    if (k + h() > dep) return 0;
    if (!p[0].r) return 1;
    int mn = p[0].r;
    for (register int i = p[0].r; i; i = p[i].r) {
        if (cnt[i] < cnt[mn])  mn = i;
    }
    for (register int i = p[mn].d; i != mn; i = p[i].d) {
        ans[k] = p[i].row;
        remove(i);
        for (register int j = p[i].r; j != i; j = p[j].r) remove(j);;
        if (dfs(k + 1, dep)) return 1;
        for (register int j = p[i].l; j != i; j = p[j].l) resume(j);
        resume(i);
    }
    return 0;
}
inline void solve() {
    cin >> n >> m;
    init();
    for (register int i = 1; i <= n; ++i) {
        int hh = tot, tt = tot;
        for (register int j = 1; j <= m; ++j) {
            int x;
            cin >> x;
            if (x) add(hh, tt, j, i);
        }
    }
    int dep = 0;
    while (!dfs(0, dep)) dep++;
    cout << dep << '\n';
    for (int i = 0; i < dep; ++i) cout << ans[i] << " ";
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. CDQ分治

P3810 【模板】三维偏序(陌上花开)

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
#define P pair
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 2e5 + 10;
struct node {
    int a, b, c, cnt, ans;
    bool operator<(node t) {
        if (a != t.a) return a < t.a;
        else if (b != t.b) return b < t.b;
        else return c < t.c;
    }
    bool operator==(node t) {
        return a == t.a && b == t.b && c == t.c;
    }
}p[N], tmp[N];
int n, k, ans[N], c[N];
int lowbit(int x) {
    return x & -x;
}
void add(int x, int y) {
    for (; x <= k; x += lowbit(x))  c[x] += y;
}
int query(int x) {
    int res = 0;
    for (; x; x -= lowbit(x)) res += c[x];
    return res;
}
void mergesort(int l, int r) {
    if (l >= r) return;
    int mid = l + r >> 1;
    mergesort(l, mid), mergesort(mid + 1, r);
    int L = l, R = mid + 1;
    int len = 0;
    while (L <= mid && R <= r) {
        if (p[L].b <= p[R].b) add(p[L].c, p[L].cnt), tmp[++len] = p[L], L++;
        else p[R].ans += query(p[R].c), tmp[++len] = p[R], R++;
    }
    while (L <= mid) add(p[L].c, p[L].cnt), tmp[++len] = p[L], L++;
    while (R <= r) p[R].ans += query(p[R].c), tmp[++len] = p[R], R++;
    for (int i = l; i <= mid; ++i) add(p[i].c, -p[i].cnt);
    for (int i = l, j = 1; j <= len; ++i, ++j) p[i] = tmp[j];
}
void solve() {
    cin >> n >> k;
    for (int i = 1; i <= n; ++i) {
        cin >> p[i].a >> p[i].b >> p[i].c;
        p[i].cnt = 1;
    }
    sort(p + 1, p + n + 1);
    int len = 0;
    for (int i = 1; i <= n; ++i) {
        if (p[i] == p[len]) p[len].cnt++;
        else p[++len] = p[i];
    }
    mergesort(1, len);
    for (int i = 1; i <= len; ++i) ans[p[i].ans + p[i].cnt - 1] += p[i].cnt;
    for (int i = 0; i < n; ++i) cout << ans[i] << '\n';
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 01Trie

P4551 最长异或路径

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
#define P pair
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 2e6 + 10;
struct edge {
    int u, v, w;
};
vector >e(N);
int tr[N][2], tot, sum[N];
void insert(int k) {
    int p = 0;
    for (int i = 30; i >= 0; --i) {
        int x = (k >> i) & 1;
        if (!tr[p][x]) tr[p][x] = ++tot;
        p = tr[p][x];
    }
}
int query(int k) {
    int p = 0, res = 0;
    for (int i = 30; i >= 0; --i) {
        int x = (k >> i) & 1;
        if (tr[p][!x]) {
            res += (1 << i);
            p = tr[p][!x];
        }
        else p = tr[p][x];
    }
    return res;
}
void dfs(int x, int fa) {
    for (auto i : e[x]) {
        if (i.v == fa) continue;
        sum[i.v] = sum[x] ^ i.w;
        insert(sum[i.v]);
        dfs(i.v, x);
    }
}
void solve() {
    int n;
    cin >> n;
    for (int i = 1; i < n; ++i) {
        int u, v, w;
        cin >> u >> v >> w;
        e[u].push_back({ u,v,w });
        e[v].push_back({ v,u,w });
    }
    dfs(1, 0);
    insert(0);
    int ans = 0;
    for (int i = 1; i <= n; ++i) {
        ans = max(ans, query(sum[i]));
    }
    cout << ans;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin >> _t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 可持久化01Trie

P4735 最大异或和

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
#define P pair
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 1e8 + 10;
int tr[N][2], tot, pre, root[N], cnt[N];
void insert(int rt, int k) {
    int p = tot, q = rt;
    for (int i = 24; i >= 0; --i) {
        tr[p][0] = tr[q][0], tr[p][1] = tr[q][1];
        int x = (k >> i) & 1;
        tr[p][x] = ++tot;
        p = tr[p][x], q = tr[q][x];
        cnt[p] = cnt[q] + 1;
    }
}
int query(int p, int q, int k) {
    int res = 0;
    for (int i = 24; i >= 0; --i) {
        int x = (k >> i) & 1;
        if (cnt[tr[q][!x]] > cnt[tr[p][!x]]) {
            res += (1 << i);
            p = tr[p][!x], q = tr[q][!x];
        }
        else p = tr[p][x], q = tr[q][x];
    }
    return res;
}
void solve() {
    int n, m;
    cin >> n >> m;
    root[0] = ++tot;
    insert(0, 0);
    for (int i = 1; i <= n; ++i) {
        int x;
        cin >> x;
        pre ^= x;
        root[i] = ++tot;
        insert(root[i - 1], pre);
    }
    for (int i = 1; i <= m; ++i) {
        char op;
        cin >> op;
        if (op == 'A') {
            int x;
            cin >> x;
            ++n;
            pre ^= x;
            root[n] = ++tot;
            insert(root[n - 1], pre);
        }
        else {
            int l, r, x;
            cin >> l >> r >> x;
            if (l == 1) cout << query(0, root[r - 1], pre ^ x) << '\n';
            else cout << query(root[l - 2], root[r - 1], pre ^ x) << '\n';
        }
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin >> _t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 树同构

P5043 【模板】树同构([BJOI2015]树的同构)

树哈希
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
#define P pair
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 55;
vector >e(N);
ll ans[N][N];
ll mask = 2333;
ll shift(ll x) {
    x ^= mask;
    x ^= x << 13;
    x ^= x >> 7;
    x ^= x << 17;
    x ^= mask;
    return x;
}
ll Hash(int x, int fa) {
    ll son[N], cnt = 0, ans = 0;
    for (int i : e[x]) {
        if (i == fa) continue;
        son[++cnt] = Hash(i, x);
    }
    sort(son + 1, son + cnt + 1);
    for (int i = 1; i <= cnt; ++i) ans = ans * 2333 + son[i];
    return ans * 2333 + 1;
    //for (int i = 1; i <= cnt; ++i) ans += shift(son[i]);
    //return ans + 1;
}
void solve() {
    int m;
    cin >> m;
    for (int i = 1; i <= m; ++i) {
        e.clear();
        e.resize(N);
        int n;
        cin >> n;
        for (int j = 1; j <= n; ++j) {
            int u;
            cin >> u;
            if (u) e[u].push_back(j), e[j].push_back(u);
        }
        for (int j = 1; j <= n; ++j) ans[i][j] = Hash(j, 0);
        sort(ans[i] + 1, ans[i] + n + 1);
        for (int j = 1; j <= i; ++j) {
            int k;
            for (k = 1; k <= n; ++k) {
                if (ans[j][k] != ans[i][k]) break;
            }
            if (k > n) {
                cout << j << '\n';
                break;
            }
        }
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
AHU算法

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long 
#define P pair
const double eps = 1e-8;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const ll N = 55;
vector >e(N);
int m, n, mn,siz[N], zx[N], cnt;
string f[N], son[N], tmp, ans[N];
void dfs1(int x, int fa) {
    siz[x] = 1;
    int tmp = 0;
    for (int i : e[x]) {
        if (i == fa) continue;
        dfs1(i, x);
        siz[x] += siz[i];
        tmp = max(tmp, siz[i]);
    }
    tmp = max(tmp, n - siz[x]);
    if (tmp < mn) {
        mn = tmp;
        cnt = 0;
        zx[++cnt] = x;
    }
    else if (tmp == mn) zx[++cnt] = x;
}
void dfs2(int x, int fa) {
    f[x] = "0";
    for (int i : e[x]) {
        if (i == fa) continue;
        dfs2(i, x);
    }
    int tot = 0;
    for (int i : e[x]) {
        if (i == fa) continue;
        son[++tot] = f[i];
    }
    sort(son + 1, son + tot + 1);
    for (int i = 1; i <= tot; ++i) f[x] += son[i];
    f[x] += "1";
    return;
}
void solve() {
    cin >> m;
    for (int i = 1; i <= m; ++i) {
        e.clear();
        e.resize(N);
        tmp = "1", mn = 0x3f3f3f3f, cnt = 0;
        cin >> n;
        for (int j = 1; j <= n; ++j) {
            int u;
            cin >> u;
            if (u) e[u].push_back(j), e[j].push_back(u);
        }
        dfs1(1, 0);
        for (int j = 1; j <= cnt; ++j) {
            dfs2(zx[j], 0);
            tmp = min(tmp, f[zx[j]]);
        }
        ans[i] = tmp;
        for (int j = 1; j <= i; ++j) {
            if (ans[j] == ans[i]) {
                cout << j << '\n';
                break;
            }
        }
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin>>_t;
    while (_t--) {
        solve();
    }
    return 0;
}
  1. 树分块

P6177 Count on a tree II/【模板】树分块

  1. 虚树

P2495 [SDOI2011] 消耗战

  1. 珂朵莉树

CF896C Willem, Chtholly and Seniorious

你可能感兴趣的:(ACM模板,数据结构,算法,c++)