【学习笔记】线段树分治

定义

线段树分治是一种解决一类有插入、删除和整体查询操作的问题的方法。它是一种离线做法,通过在线段树上记录操作的时间区间来处理修改对询问的影响。每个操作被看作一个时间区间的修改,并在线段树上进行标记。然后通过深度优先搜索(DFS)依次执行这些操作,直到根节点来回答查询,并在离开时将其撤销。

题目

#121. 「离线可过」动态图连通性

#include <bits/stdc++.h>
#define fo(a,b,c) for(int a=b;a<=c;a++)
#define re(a,b,c) for(int a=b;a>=c;a--)
#define mod 1000000007
#define inp 10000019
using namespace std;
const int N = 500005;

inline int read() {
    int x = 0, f = 1;
    char ch = getchar();

    while (ch < '0' || ch > '9') {
        if (ch == '-')
            f = -1;

        ch = getchar();
    }

    while (ch >= '0' && ch <= '9') {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }

    return x * f;
}

int nyn = 1;
int n, e[5005][5005], cnt, st[N], en[N], fr[N], to[N], f[N];
int op2l[N], op2r[N], sz[N], tot;

struct sss {
    int x, y, szx, szy;
} sta[N];

int find(int x) {
    if (f[x] == x)
        return x;

    return find(f[x]);
}

void merge(int x, int y) {
    x = find(x);
    y = find(y);

    if (x == y)
        return;

    tot++;

    if (sz[x] > sz[y])
        swap(x, y);

    sta[tot].x = x;
    sta[tot].y = y;
    sta[tot].szx = sz[x];
    sta[tot].szy = sz[y];
    f[x] = y;
    sz[y] += sz[x];
}

void split(int k) {
    while (tot > k) {
        int x = sta[tot].x, y = sta[tot].y;
        int szx = sta[tot].szx;
        int szy = sta[tot].szy;
        f[x] = x;
        sz[x] = szx;
        sz[y] = szy;
        tot--;
    }
}

struct IO {
    vector<int> t;
} node[N * 4];

void ud(int rt, int l, int r, int L, int R, int val) {
    if (l > r)
        return;

    if (L <= l && r <= R) {
        node[rt].t.push_back(val);
        return;
    }

    int mid = (l + r) / 2;

    if (L <= mid)
        ud(rt * 2, l, mid, L, R, val);

    if (R >= mid + 1)
        ud(rt * 2 + 1, mid + 1, r, L, R, val);
}

void qr(int rt, int l, int r) {
    int num = tot;

    for (int i = 0; i < node[rt].t.size(); i++) {
        int x = node[rt].t[i];
        merge(fr[x], to[x]);
    }

    if (l == r) {
        if (l == 1)
            return;

        int x = op2l[l], y = op2r[l];
        int fx = find(x), fy = find(y);

        if (fx == fy)cout << "Y\n";
        else cout << "N\n";

        split(num);
        return;
    }

    int mid = (l + r) / 2;
    qr(rt * 2, l, mid);
    qr(rt * 2 + 1, mid + 1, r);
    split(num);
}

int dp[N];
void sol() {
    n = read();

    for (int i = 1; i <= n; i++)
        f[i] = i, sz[i] = 1;

    int m = read();
    int tm = 1;

    for (int i = 1; i <= m; i++) {
        int op = read();

        if (op == 0) {
            cnt++;
            int x = read();
            int y = read();
            fr[cnt] = x;
            to[cnt] = y;
            e[x][y] = e[y][x] = cnt;
            st[cnt] = tm + 1;
        } else if (op == 1) {
            int x = read();
            int y = read();
            en[e[x][y]] = tm;
            e[x][y] = 0;
        } else {
            tm++;
            op2l[tm] = read();
            op2r[tm] = read();
        }
    }

    for (int i = 1; i <= cnt; i++)
        if (en[i])
            ud(1, 1, tm, st[i], en[i], i);
        else
            ud(1, 1, tm, st[i], tm, i);

    qr(1, 1, tm);
}

int main() {
    while (nyn--) {
        sol();
        printf("\n");
    }
}

P5787 二分图 /【模板】线段树分治
https://www.luogu.com.cn/blog/xzc/xian-duan-shu-fen-zhi

嘻嘻,结束!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值