zoukankan      html  css  js  c++  java
  • 线段树分治

    有一类问题,需要支持插入,删除等一些操作。

    可能插入比较容易,但是怎么想都不能删除,这时候就需要用到线段树分治了。

    具体怎么做?

    按操作时间建立一棵线段树。

    线段树上每一个节点用 vector 存下一些操作,表示这些操作在这个节点所代表的时间区间生效。

    插入完操作后,开始遍历线段树。

    进入线段树的一个节点时,加入所有的操作,并在加入操作之前记录下原来的状态(也可以开 vector 记录)。

    到根节点时,一个时间点的所有操作都加入完毕,此时可以进行查询操作了。

    回溯时要记得还原成未加入操作前的状态。

    分析一下复杂度

    由于一次操作会在时间线段树上 (log n) 个节点产生贡献,所以复杂度比平常应该是多了一个 (log)

    撤销操作一般复杂度都要小于等于插入操作,所以能插入一般都能撤回。

    代码

    感觉这道例题可能难点在于带权并查集上,这里挂几篇写的比较好的博客吧。

    带权并查集1

    带权并查集2

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 1e5 + 5;
    const int M = 2e5 + 5;
    
    int n, m, k;
    
    struct edge { int x, y; } ;
    
    int ou[M], od[M], odist[M], top;
    
    namespace UFS {
        int fa[N], d[N], dist[N];
        int find(int u) { return fa[u] == u ? u : find(fa[u]); }
        int getDist(int u) { return fa[u] == u ? 0 : dist[u] ^ getDist(fa[u]); }
        bool merge(int u, int v) {
            int x = find(u), y = find(v);
            if(x == y) return false;
            if(d[x] > d[y]) swap(u, v), swap(x, y);
            ++top;
            ou[top] = x, od[top] = d[y], odist[top] = dist[x];
            dist[x] = getDist(u) ^ getDist(v) ^ 1, fa[x] = y, d[y] += (d[x] == d[y]); 
            return true; 
        }
        void undo() {
            int u = ou[top];
            d[fa[u]] = od[top];
            dist[u] = odist[top];
            fa[u] = u;
            --top;
        }
    }
    
    int ll, rr;
    edge ce;
    
    namespace SMT {
        #define lch(x) (x << 1)
        #define rch(x) (x << 1 | 1)
        vector<edge> e[N << 2];
        void modify(int u, int l, int r) {
            if(ll <= l && r <= rr) {
                e[u].push_back(ce);
                return void();
            }
            int mid = (l + r) >> 1;
            if(ll <= mid) modify(lch(u), l, mid);
            if(mid < rr) modify(rch(u), mid + 1, r);
        }
        void dfs(int u, int l, int r) {
            int ecnt = 0; 
            bool flag = false; 
            for(size_t i = 0; i < e[u].size(); ++i) {
                int x = e[u][i].x, y = e[u][i].y;
                if(!UFS::merge(x, y)) {
                    flag |= (UFS::getDist(x) == UFS::getDist(y)); 
                    if(flag) break;
                } else {
                    ++ecnt;
                }
            }
            if(flag) for(int i = l; i <= r; ++i) puts("No");
            else if(l == r) puts("Yes");
            else {
                int mid = (l + r) >> 1;
                dfs(lch(u), l, mid);
                dfs(rch(u), mid + 1, r);
            }
            for(int i = 1; i <= ecnt; ++i)
                UFS::undo();
        }
    }
    
    int main() {
        scanf("%d %d %d", &n, &m, &k);
        for(int i = 1; i <= n; ++i)
            UFS::fa[i] = i;
        for(int i = 1, x, y, l, r; i <= m; ++i) {
            scanf("%d %d %d %d", &x, &y, &l, &r);
            ce = (edge){x, y};
            ll = l + 1, rr = r;
            if(ll <= rr) SMT::modify(1, 1, k);
        }
        SMT::dfs(1, 1, k);
        return 0;
    }
    
    
  • 相关阅读:
    PG-日常管理
    PG-高可用(pgpool-Ⅱ)
    PG-基准测试
    PG-备份恢复
    PG-并发问题
    Go-常量
    Go-变量
    Oracle-11g升级PSU补丁
    Oracle-`sqlplus`工具使用技巧
    [CF1051F] The Shortest Statement
  • 原文地址:https://www.cnblogs.com/Lskkkno1/p/12923677.html
Copyright © 2011-2022 走看看