【笔记】数据结构优化建图(Deepseek 生成)

数据结构优化建图

线段树优化建图

适用场景

处理点与区间、区间与区间之间的连边问题(如:点 \(u\) 向区间 \([L,R]\) 内所有点连边)

实现原理

  1. 建立两棵线段树
    • 入树(in_tree):处理流入区间的边
    • 出树(out_tree):处理流出区间的边
  2. 节点关系:线段树内部父节点与子节点双向连接(边权为0)
  3. 时间复杂度:将边数从 \(O(n^2)\) 优化到 \(O(n \log n)\)

C++20 实现

#include <vector>
using namespace std;

struct Edge { int to, w; };
const int N = 1e5 * 20; // 预估节点数

class SegTreeGraph {
    vector<Edge> G[N];
    int in_id[N], out_id[N];
    int node_cnt = 0;

    void build(int p, int l, int r, bool is_in) {
        if(l == r) {
            (is_in ? in_id[l] : out_id[l]) = p;
            return;
        }
        int mid = (l + r) >> 1;
        build(p<<1, l, mid, is_in);
        build(p<<1|1, mid+1, r, is_in);
        // 建立树内边
        G[p].emplace_back(p<<1, 0);
        G[p].emplace_back(p<<1|1, 0);
        if(!is_in) { // 出树需要反向边
            G[p<<1].emplace_back(p, 0);
            G[p<<1|1].emplace_back(p, 0);
        }
    }

public:
    SegTreeGraph(int n) {
        build(1, 1, n, true);   // 构建入树
        build(1, 1, n, false);  // 构建出树
    }

    void add_edge(int u, int l, int r, int w, bool is_out) {
        auto connect = [&](auto&& self, int p, int L, int R) {
            if(l <= L && R <= r) {
                is_out ? G[u].push_back({p, w}) 
                      : G[p].push_back({u, w});
                return;
            }
            int mid = (L + R) >> 1;
            if(l <= mid) self(self, p<<1, L, mid);
            if(r > mid) self(self, p<<1|1, mid+1, R);
        };
        connect(connect, 1, 1, n);
    }
};

前缀优化建图

适用场景

处理连续前缀/后缀的批量连边(如:点 \(v\) 需要向 \(1 \sim k\) 所有点连边)

C++20 实现

class PrefixGraph {
    vector<Edge> G[N];
    int pre[N]; // 前缀虚点
    
public:
    void build(int n) {
        pre[0] = -1;
        for(int i=1; i<=n; ++i) {
            pre[i] = ++node_cnt;
            G[pre[i]].emplace_back(pre[i-1], 0); // 继承前驱
            G[pre[i]].emplace_back(i, 0);        // 连接当前点
        }
    }

    void add_prefix(int u, int k, int w) {
        G[u].emplace_back(pre[k], w);
    }
};

分治优化建图

C++20 实现

class DivideGraph {
    vector<Edge> G[N];
    int node_cnt = 0;
    
    void build(int l, int r) {
        if(l == r) return;
        int mid = (l + r) >> 1;
        int cur = ++node_cnt;
        
        for(int i=l; i<=mid; ++i)
            G[i].emplace_back(cur, 0);
        for(int i=mid+1; i<=r; ++i)
            G[cur].emplace_back(i, 0);
        
        build(l, mid);
        build(mid+1, r);
    }
};

倍增优化建图

C++20 实现

class JumpGraph {
    vector<Edge> G[N][18]; // G[i][k] 表示i的第2^k层连接
    
public:
    void add_base_edge(int u, int v, int w) {
        G[u][0].emplace_back(v, w);
    }

    void build(int n) {
        for(int j=1; j<18; ++j)
            for(int i=1; i<=n; ++i)
                for(auto [p, w1] : G[i][j-1])
                    for(auto [q, w2] : G[p][j-1])
                        G[i][j].emplace_back(q, w1 + w2);
    }
};

主席树优化建图

C++20 实现

struct PersistentNode {
    int lc, rc;
    vector<Edge> edges;
} T[N * 20];

class PersistentGraph {
    int roots[N], tot = 0;
    
public:
    int update(int prev, int l, int r, int pos, int v, int w) {
        int p = ++tot;
        T[p] = T[prev];
        if(l == r) {
            T[p].edges.emplace_back(v, w);
            return p;
        }
        int mid = (l + r) >> 1;
        if(pos <= mid) T[p].lc = update(T[p].lc, l, mid, pos, v, w);
        else T[p].rc = update(T[p].rc, mid+1, r, pos, v, w);
        return p;
    }
};

复杂度对比

优化方法 边数复杂度 空间复杂度
线段树优化 \(O(n \log n)\) \(O(n \log n)\)
前缀优化 \(O(n)\) \(O(n)\)
分治优化 \(O(n \log n)\) \(O(n \log n)\)
倍增优化 \(O(n \log K)\) \(O(n \log K)\)
主席树优化 \(O(q \log n)\) \(O(q \log n)\)

注:代码实现采用零开销抽象原则,实际使用时需根据问题规模调整预分配空间

posted @ 2025-02-27 16:51  GuTongXing  阅读(44)  评论(0)    收藏  举报