zoukankan      html  css  js  c++  java
  • 常用数据结构整理

    数据结构

    线性结构

    单调队列

    滑动窗口优化 DP

    例题 LOJ 10180. 「一本通 5.5 练习 1」烽火传递

    给定一个数轴,上面有 n 个点,选中每个点有一定代价,现要求连续的 m 个点中至少选一个,求最小代价。

    /**
     *
     * 考虑 dp
     * 设 dp[i] 表示选择第 i 个来保证 [1, i] 合法的最小花费
     * 转移方程:
     * dp[i] = cost[i] + min{dp[j]} (i - m <= j < i)
     * 后面这个 min 可以滑动窗口优化
     *  
     */
    
    const int MAXN = 2e5 + 10;
    
    int q1[MAXN], q2[MAXN];
    int h1 = 1, t1 = 1, h2 = 1, t2 = 1; // 左闭右开
    
    int n, m;
    int ss[MAXN];
    int dp[MAXN];
    
    int main() {
        n = read(); m = read();
        for (int i = 1; i <= n; ++i) ss[i] = read();
        for (int i = 1; i <= n; ++i) {
            // 队尾弹出不优的,维护单调性
            while (h1 != t1 && q1[t1 - 1] >= dp[i - 1]) --t1, --t2;
            // 队尾入队
            q1[t1++] = dp[i - 1]; q2[t2++] = i - 1;
            // 队头弹出过期的
            while (h2 != t2 && q2[h2] < i - m) ++h1, ++h2;
            // 更新答案
            dp[i] = ss[i] + q1[h1];
        }
        int ans = 0x7f7f7f7f;
        for (int i = n - m + 1; i <= n; ++i) ans = std::min(ans, dp[i]);
        printf("%d
    ", ans);
        return 0;
    }
    

    ST 表

    const int MAXN = (100000 + 10) * 2;
    const int MAXLOG = 17 + 10; // floor(log2(100000 + 10))
    
    int n, q;
    int Table[MAXN][MAXLOG];
    
    void BuildTable() {
        for (int j = 1; (1 << j) <= n; ++j) {
            for (int i = 1; i + (1 << j) - 1 <= n; ++i) {
                Table[i][j] = std::max(Table[i][j-1], Table[i + (1 << (j - 1))][j - 1]);
            }
        }
    }
    
    int Query(int l, int r) {
        int k = std::log(r - (l - 1)) / std::log(2);
        return std::max(Table[l][k], Table[r - ((1 << k) - 1)][k]);
    }
    
    int main() {
        scanf("%d %d", &n, &q);
        for (int i = 1; i <= n; ++i) scanf("%d", &Table[i][0]);
        BuildTable();
        for (int i = 1; i <= q; ++i) {
            int l = 0, r = 0;
            scanf("%d %d", &l, &r);
            printf("%d
    ", Query(l, r));
        }
        return 0;
    }
    

    分块

    区间加法,单点查询

    const int MAXN = 50000 + 10;
    
    int n;
    int ss[MAXN];
    
    namespace Blocks {
        int blk[MAXN], add[MAXN]; int siz;
    
        int blkFirst(int id) { // id 属于的块开始位置的编号
            return (blk[id] - 1) * siz + 1;
        }
        int blkLast(int id) { // id 属于的块结束位置的编号
            return blk[id] * siz;
        }
        void init() {
            siz = std::sqrt(n);
            for (int i = 1; i <= n; ++i) blk[i] = (i - 1) / siz + 1;
        }
        void Add(int l, int r, int k) {
            for (int i = l; i <= std::min(blkLast(l), r); ++i) {
                ss[i] += k;
            }
            if (blk[l] != blk[r]) {
                for (int i = blkFirst(r); i <= r; ++i) {
                    ss[i] += k;
                }
            }
            for (int i = blk[l] + 1; i <= blk[r] - 1; ++i) add[i] += k;
        }
        int Query(int r) {
            return add[blk[r]] + ss[r];
        }
    }
    

    树图结构

    并查集

    struct DSU {
        int seq[MAXN];
    
        int Find(int x) { return !seq[x] ? x : seq[x] = Find(seq[x]); }
        void Merge(int x, int y) {
            x = Find(x); y = Find(y);
            if (x != y) seq[x] = y;
        }
    } dsu;
    

    线段树

    struct SegtTree {
        int sum[MAXN << 2]; int tag[MAXN << 2];
    
    #define ls (p << 1)
    #define rs (p << 1 | 1)
    
        void Update(int p) { sum[p] = sum[ls] + sum[rs]; }
        void buildTree(int p, int l, int r, int *k) {
            if (l == r) { sum[p] = k[l]; return; }
            int mid = (l + r) >> 1;
            buildTree(ls, l, mid, k); buildTree(rs, mid + 1, r, k);
            Update(p);
        }
        void Add(int p, int l, int r, int k) {
            (sum[p] += 1ll * k * (r - l + 1) % ha) %= ha;
            (tag[p] += k) %= ha;
        }
        void Pushdown(int p, int l, int r) {
            if (tag[p]) {
                int mid = (l + r) >> 1;
                Add(ls, l, mid, tag[p]); Add(rs, mid + 1, r, tag[p]);
                tag[p] = 0;
            }
        }
        void Modify(int p, int l, int r, int ll, int rr, int k) {
            if (l == ll && rr == r) { Add(p, l, r, k); return; }
            Pushdown(p, l, r);
            int mid = (l + r) >> 1;
            if (rr <= mid) Modify(ls, l, mid, ll, rr, k);
            else if (mid + 1 <= ll) Modify(rs, mid + 1, r, ll, rr, k);
            else { Modify(ls, l, mid, ll, mid, k); Modify(rs, mid + 1, r, mid + 1, rr, k); }
            Update(p);
        }
        int Query(int p, int l, int r, int ll, int rr) {
            if (l == ll && rr == r) return sum[p] % ha;
            Pushdown(p, l, r);
            int mid = (l + r) >> 1;
            if (rr <= mid) return Query(ls, l, mid, ll, rr) % ha;
            else if (mid + 1 <= ll) return Query(rs, mid + 1, r, ll, rr) % ha;
            else return (Query(ls, l, mid, ll, mid) + Query(rs, mid + 1, r, mid + 1, rr)) % ha;
        }
    } segt;
    

    树状数组

    区间加法

    int n, tree[MAX_SIZE];
    // n 为元素个数,tree[] 为树状数组维护的前缀和
    
    int lowbit(int x) { return (x) & (-x); }
    
    void Modify(int pos, int x) {
        // 将 pos 位置的数加上 x
        for (; pos <= n; pos += lowbit(pos)) tree[pos] += x;
    }
    
    int Query(int pos) {
        // 查询 [1,pos] 之间的数的和
        int ret = 0;
        for (; pos >= 1; pos -= lowbit(pos)) ret += tree[pos];
        return ret;
    }
    
    int rangeQuery(int l, int r) {
        // 查询 [l,r] 之间的数的和
        return Query(r) - Query(l - 1);
    }
    

    Trie 树

    struct Trie {
        static const int MAXNODE = 300000 + 10;
    
        struct Node {
            int cntson; bool end;
            int next[27];
            Node() { end = cntson = 0; memset(next, 0, sizeof next); }
        } node[MAXNODE]; const int root = 1; int cnt = 1;
    
        void Insert(const std::string &x) {
            int len = (int) x.size(); int u = root;
            for (int i = 0; i < len; ++i) {
                int &nxt = node[u].next[x[i] - 'a'];
                if (!nxt) nxt = ++cnt, ++node[u].cntson;
                u = nxt;
            } node[u].end = true;
        }
    } trie;
    

    哈希算法

    字符串哈希

    struct Hash {
      static const int b1 = 29;
      static const int b2 = 131;
      static const int m1 = 998244353;
      static const int m2 = 1e9 + 7;
    
      int h1, h2;
      Hash() { h1 = h2 = 0; }
      void append(int x) {
          h1 = 1ll * h1 * b1 % m1 + x; h1 %= m1;
          h2 = 1ll * h2 * b2 % m2 + x; h2 %= m2;
      }
      void erase_prefix(Hash x, int len) {
          h1 -= 1ll * x.h1 * pb1[len - 1] % m1; h1 += m1; h1 %= m1;
          h2 -= 1ll * x.h2 * pb2[len - 1] % m2; h2 += m2; h2 %= m2; 
      }
      bool operator == (const Hash &th) const {
          return h1 == th.h1 && h2 == th.h2;
      }
    };
    

    手写哈希表

    int _RND = 0;
    
    srand(time(0));
    _RND = std::abs(rand() * rand() % 998244353);
    
    struct HashMap {
        static const int SZ = 1926097;
        struct data {
            long long u;
            int v, nex;
            data(long long _u = 0, int _v = 0, int _nex = 0) {
                u = _u; v = _v; nex = _nex;
            }
        };
        data e[SZ << 1];
        int h[SZ], cnt;
        int hash(long long u) { return u % SZ; }
        bool locate(long long u) {
            int hu = hash(u ^ _RND);
            for (int i = h[hu]; i; i = e[i].nex) {
                if (e[i].u == u) return true;
            }
            return false;
        }
        int& operator[](long long u) {;
            int hu = hash(u ^ _RND);
            for (int i = h[hu]; i; i = e[i].nex)
                if (e[i].u == u) return e[i].v;
            return e[++cnt] = (data) {u, 0, h[hu]}, h[hu] = cnt, e[cnt].v;
        }
        HashMap() {
            cnt = 0;
            memset(h, 0, sizeof(h));
        }
    } mp;
    
  • 相关阅读:
    0302思考并回答一些问题
    0104 自下而上
    1203 有穷自动机的构造
    11 10我的评论
    1029 C语言文法翻译(2)
    1014 对编译程序的心得与总结
    我们小组的编译程序
    0921 词法分析程序
    0909 关于编译原理的思考
    数据库设计之数据库设计三大范式
  • 原文地址:https://www.cnblogs.com/handwer/p/15388487.html
Copyright © 2011-2022 走看看