背板子

博客介绍了几种算法模板,包括lca转rmq,通过欧拉遍历记录dep并建立ST表查询dep最小值;后缀数组SA,强调sa、rk和tp数组的使用;还提及exgcd和tarjan缩点,其中tarjan缩点内容待补充。

lca转rmq

欧拉遍历,记录dep,然后建立ST表查询第一次出现位置之间的dep最小值
定义一个mindep会方便很多

const int N = 100005, E = 200005;
int to[E], nt[E], hd[N], ord[E], dep[N], fa[N], fst[N], tot = 0, Index = 0;
int st[18][E], lg[E];
void dfs(int x){
    ord[++Index] = x; fst[x] = Index;
    for(int i=hd[x]; i; i=nt[i]){
        if(to[i] == fa[x]) continue;
        fa[to[i]] = x; dep[to[i]] = dep[x] + 1;
        dfs(to[i]);
        ord[++Index] = x;
    }
}
#define mindep(x, y) (dep[x] < dep[y] ? (x) : (y))
void build_st(){
    for(int i=2; i<=Index; i<<=1) ++lg[i];
    for(int i=1; i<=Index; i++) lg[i] += lg[i-1], st[0][i] = ord[i];
    for(int i=1; i<=lg[Index]; i++)
        for(int j=1; j<=Index; j++)
            st[i][j] = j + (1 << i) - 1 > Index ? 0 : mindep(st[i-1][j], st[i-1][j + (1 << (i - 1))]);
}
int rmq(int x, int y){return mindep(st[lg[y-x+1]][x], st[lg[y-x+1]][y - (1 << lg[y-x+1]) + 1]);}
int lca(int x, int y){return fst[x] <= fst[y] ? rmq(fst[x], fst[y]) : rmq(fst[y], fst[x]);}

后缀数组,SA

sa,rk两个数组不能混,tp是第二关键字

#include <cstring>
using namespace std;
const int N = 1000005;
int chmap[128], s[N], sa[N], rk[N], tp[N], cnt[N], n, m;
void rsort(){
    for(int i=0; i<=m; i++) cnt[i] = 0;
    for(int i=1; i<=n; i++) ++cnt[rk[i]];
    for(int i=1; i<=m; i++) cnt[i] += cnt[i-1];
    for(int i=n; i>=1; i--) sa[cnt[rk[tp[i]]]--] = tp[i];
}
void getSA(){
    m = 63;
    for(int i=1; i<=n; i++) rk[i] = s[i], tp[i] = i;
    rsort();
    for(int w=1, p = 0; p < n; m = p, w <<= 1){
        p = 0;
        for(int i=1; i<=w; i++) tp[++p] = n - w + i;
        for(int i=1; i<=n; i++) if(sa[i] > w) tp[++p] = sa[i] - w;
        rsort();
        memcpy(tp, rk, sizeof tp);
        rk[sa[1]] = p = 1;
        for(int i=2; i<=n; i++)
            rk[sa[i]] = (tp[sa[i-1]] == tp[sa[i]] && (sa[i-1] + w <= n && sa[i] + w <= n && tp[sa[i-1] + w] == tp[sa[i] + w])) ? p : ++p;
    }
}

exgcd

int exgcd(int a, int b, int &x, int &y){
    if(b == 0){
        x = 1; y = 0;
        return a;
    }
    int result = exgcd(b, a%b, x, y);
    int tp = x; x = y; y = tp - a/b*y;
    return result;
}

tarjan缩点

void tarjan(int x){
    low[x] = dfn[x] = ++id;
    stk[++top] = x; instk[x] = true;
    for(int i=hd[x]; i; i=nt[i]){
        if(dfn[to[i]] == 0) tarjan(to[i]), low[x] = min(low[x], low[to[i]]);
        else if(instk[to[i]]) low[x] = min(low[x], dfn[to[i]]);
    }
    if(low[x] == dfn[x]){
        ++color; col[x] = color;
        while(stk[top] != x) instk[stk[top]] = false, col[stk[top--]] = color;
        top--; instk[x] = false;
    }
}

待补充...

转载于:https://www.cnblogs.com/RiverHamster/p/algorithm-template.html

### 蓝桥杯备赛所需算法模板合集 以下是针对蓝桥杯比赛整理的一些重要算法模板及其相关内容: #### 1. 数学基础 - **最大公约数 (GCD)** 计算两个整数的最大公约数可以使用辗转相除法。 ```cpp int gcd(int a, int b) { return b ? gcd(b, a % b) : a; } ``` [^2] - **扩展欧几里得算法 (EXGCD)** 用于解线性同余方程 \( ax + by = \gcd(a, b) \) 的一组特解。 ```cpp void exgcd(int a, int b, int &x, int &y) { if (!b) { x = 1; y = 0; return; } exgcd(b, a % b, y, x); y -= a / b * x; } ``` - **最小公倍数 (LCM)** 通过 GCD 计算 LCM,注意防止溢出。 ```cpp long long lcm(long long a, long long b) { return a / gcd(a, b) * b; } ``` #### 2. 排序与查找 - **Dijkstra 算法** 适用于单源最短路径问题,支持优先队列优化版本。 ```cpp #include <queue> const int INF = 0x3f3f3f3f; struct Node { int u, dis; bool operator<(const Node& rhs) const { return dis > rhs.dis; } }; std::vector<std::pair<int, int>> adj[N]; bool vis[N]; int dist[N]; void dijkstra(int start) { std::priority_queue<Node> pq; memset(dist, 0x3f, sizeof(dist)); dist[start] = 0; pq.push({start, 0}); while(!pq.empty()) { auto cur = pq.top(); pq.pop(); int u = cur.u; if(vis[u]) continue; vis[u] = true; for(auto &[v, w] : adj[u]) { if(dist[v] > dist[u] + w){ dist[v] = dist[u] + w; pq.push({v, dist[v]}); } } } } ``` [^1] - **Kruskal 算法** 实现最小生成树的经典方法之一,基于并查集操作。 ```cpp struct Edge { int u, v, w; }; Edge edges[M]; int fa[N]; int find_set(int x) { return fa[x] == x ? x : fa[x] = find_set(fa[x]); } void kruskal() { sort(edges, edges + m); // 按权重从小到大排序 for(int i=1;i<=n;i++) fa[i]=i; ll res=0,cnt=0; for(int i=0;i<m && cnt<n-1;i++){ int fx=find_set(edges[i].u),fy=find_set(edges[i].v); if(fx!=fy){ fa[fy]=fx; res+=edges[i].w; cnt++; } } } ``` #### 3. 动态规划 - **01 包问题** 解决有限容量下的最优价值分配问题。 ```cpp for(int i=1;i<=n;i++) for(int j=m;j>=w[i];j--) dp[j]=max(dp[j],dp[j-w[i]]+v[i]); ``` - **完全包问题** 允许每种物品无限次选取的情况。 ```cpp for(int i=1;i<=n;i++) for(int j=w[i];j<=m;j++) dp[j]=max(dp[j],dp[j-w[i]]+v[i]); ``` #### 4. 字符串处理 - **Trie(字典树)结构** 适合存储大量字符串数据,便于查询和统计。 ```cpp struct TrieNode{ int next[26]; int count; } trie[MAX_NODE]; int node_cnt = 1; void insert(const string &str){ int p = 1; for(char ch:str){ int idx = ch-'a'; if(trie[p].next[idx]==0){ trie[p].next[idx] = ++node_cnt; } p = trie[p].next[idx]; } trie[p].count++; } ``` #### 5. Python 高精度运算 Python 自带高精度特性,在蓝桥杯比赛中无需额外考虑数值范围限制。 ```python def factorial(n): result = 1 for i in range(1, n+1): result *= i return result ``` [^3] --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值