ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

常用数据结构整理

2021-10-10 08:31:06  阅读:94  来源: 互联网

标签:常用 const int void h1 h2 整理 return 数据结构


数据结构

线性结构

单调队列

滑动窗口优化 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;

标签:常用,const,int,void,h1,h2,整理,return,数据结构
来源: https://www.cnblogs.com/handwer/p/15388487.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有