常用数据结构整理

数据结构

线性结构

单调队列

滑动窗口优化 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\n", 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\n", 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;
上一篇:CF123D String [SAM]


下一篇:实验6:开源控制器实践——RYU