OI 模板合集

快速输入输出(IO)

cin/cout 加速
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int 快读
inline int read() {
    int x = 0, f = 1; // f 标记正负(1 正 / -1 负)
    char ch = getchar();
    while (ch < '0' || ch > '9') { // 过滤乱码及确定正负
        if (ch == '-') f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = (x << 1) + (x << 3) + (ch ^ 48); // 前两项为(2+8)x=10x,第三项相当于ch-'0'
        ch = getchar();
    }
    return f * x;
}

inline void Read(int &t) {
    t = read();
}
int 快写
inline void write(int x) {
    if (x < 0) putchar('-'), x = -x;
    if (x > 9) write(x / 10);
    putchar(x % 10 + '0');
}

inline void Write(int x) {
    write(x);
    putchar('\n');
}

基础算法

前缀和
for (int i = 1; i <= n; i ++) {
  cin >> arr[i];
  sum[i] = sum[i - 1] + arr[i];
}
差分
for (int i = 1; i <= n; i ++) {
    cin >> arr[i];
    dif[i] = arr[i] - arr[i - 1];
}
二分答案
int l = 0, r = 1e9, ans = 0;
while (l <= r) {
    int mid = (l + r) / 2;
    if (check(mid)) {
        ans = mid;
        r = mid - 1;
    } else {
        l = mid + 1;
    }
}
二分查找
int binary_search(int target) {
    int l = 1, r = n, mid = -1;
    while (l <= r) {
        mid = (l + r) >> 1;
        if (arr[mid] == target) return mid;
        else if (arr[mid] < target) l = mid + 1;
        else r = mid - 1;
    }
    return mid;
}
可分割背包(贪心)
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;

typedef long long ll;
ll n, t;
struct Node {
    ll m, v; // 重量、价值
    double a; // 单位价格
} a[105];

bool cmp(Node ta, Node tb) {
    return ta.a > tb.a;
}

int main() {
    cin >> n >> t;
    for (int i = 1; i <= n; i ++) {
        cin >> a[i].m >> a[i].v;
        a[i].a = 1.0 * a[i].v / a[i].m;
    }

    sort(a + 1, a + n + 1, cmp);

    ll left = t;
    double ans = 0.0;
    for (int i = 1; i <= n; i ++) {
        ll am = min(a[i].m, left);
        left -= am;
        ans += am * a[i].a;
        if (left == 0) break;
    }
    printf("%.2lf\n", ans);
    return 0;
}

搜索枚举

dfs 枚举排列
int n, k;
int per[n];
bool vis[n];
void dfs(int dep) {
    if (dep == k) {
        for (int i = 0; i < k; i ++) {
            cout << per[i] << " ";
        }
        cout << endl;
        return;
    }
    for (int i = 1; i <= n; i ++) {
        if (vis[i]) continue;
        vis[i] = true;
        per[dep] = i;
        dfs(dep + 1);
        vis[i] = false;
    }
}
dfs 枚举组合
int n, k;
int comb[N];
void dfs(int x, int dep) {
    if (dep == k) {
        for (int i = 0; i < k; i ++) {
            cout << comb[i] << " ";
        }
        cout << endl;
        return;
    }
    if (x > n) return;
    comb[dep] = x;
    dfs(x + 1, dep + 1);
    dfs(x + 1, dep);
}
bfs 走迷宫
typedef pair<int, int> PII;
int n, m;
int arr[105][105]; // 0 -> 空地;1 -> 障碍
bool vis[105][105];
int cx[] = {0, 0, 1, -1};
int cy[] = {1, -1, 0, 0};
bool found = false;
void bfs() {
	queue<PII> q;
	q.push({1, 1});
	while (!q.empty()) {
		PII cur = q.front();
		q.pop();
		int x = cur.first, y = cur.second;
		if (x < 1 || x > n || y < 1 || y > m) continue;
		if (arr[x][y] == 1) continue;
		if (vis[x][y]) continue;
		vis[x][y] = true;
		if (x == n && y == m) {
			found = true;
			return;
		}

		for (int i = 0; i < 4; i ++) {
			q.push({x + cx[i], y + cy[i]});
		}
	}
}

动态规划

01 背包 $w$ 表示重量,$v$ 表示价值,$N$ 表示物品个数,$W$ 表示背包容量,$f$ 表示 $dp$ 数组
for (int i = 1; i <= N; i ++) {
    for (int j = W; j >= w[i]; j --)
        f[j] = max(f[j], f[j - w[i]] + v[i]);
}
完全背包 $w$ 表示重量,$v$ 表示价值,$N$ 表示物品个数,$W$ 表示背包容量,$f$ 表示 $dp$ 数组
for (int i = 1; i <= N; i ++) {
    for (int j = w[i]; j <= W; j ++)
        f[j] = max(f[j], f[j - w[i]] + v[i]);
}
二维费用背包
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
ll H, T, n; // 体积最大值,质量最大值,物品个数
ll dp[405][405]; // 体积为 i,质量为 j 所能承载的最大价值
ll h[55]; // 体积
ll t[55]; // 质量
ll k[55]; // 价值

int main() {
	cin >> H >> T >> n;
    for (int i = 1; i <= n; i ++) {
        cin >> h[i] >> t[i] >> k[i];
    }

    for (int l = 1; l <= n; l ++) {
        for (int i = H; i >= h[l]; i --) {
            for (int j = T; j >= t[l]; j --) {
                dp[i][j] = max(dp[i][j], dp[i - h[l]][j - t[l]] + k[l]);
            }
        }
    }
    cout << dp[H][T] << endl;
	return 0;
}
分组背包
#include <iostream>
#include <vector>
using namespace std;

int dp[1010], n[21];
vector<int> w[21], c[21];

int main() {
    int K, V;
    cin >> K >> V;
    for (int i = 1; i <= K; i ++) {
        cin >> n[i];
        for (int j = 0; j < n[i]; j ++) {
            int worth, cost;
            cin >> worth >> cost;
            w[i].push_back(worth);
            c[i].push_back(cost);
        }
    }
    
    for (int i = 1; i <= K; i ++) {
        for (int j = V; j >= 0; j --) {
            for (int k = 0; k < n[i]; k ++) {
                if (j >= c[i][k]) {
                    dp[j] = max(dp[j], dp[j - c[i][k]] + w[i][k]);
                }
            }
        }
    }

    cout << dp[V] << endl;
    return 0;
}
多重背包(无二进制优化)
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
ll dp[105];
ll weight[10004], value[10004], sum = 0;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    ll N, V;
    cin >> N >> V;
    for (ll i = 1; i <= N; i++) {
        ll tweight, tvalue, s;
        cin >> tweight >> tvalue >> s;
        for (ll j = 1; j <= s; j ++) {
            sum ++;
            weight[sum] = tweight;
            value[sum] = tvalue;
        }
    }
    for (ll i = 1; i <= sum; i++) {
        for (ll j = V; j >= weight[i]; j --) {
            dp[j] = max(dp[j - weight[i]] + value[i], dp[j]);
        }
    }
    cout << dp[V] << endl;
    return 0;
}
多重背包(有二进制优化)
#include <iostream>
#include <cstring>
using namespace std;

typedef long long ll;
ll dp[20005];
ll weight[11000], value[11000], sum = 0;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    ll N, V;
    cin >> N >> V;
    for (ll i = 1; i <= N; i++) {
        ll tweight, tvalue, s;
        cin >> tweight >> tvalue >> s;
        if (s == 0) s = 1000;
        ll rate = 1;
        while (rate <= s) {
            sum ++;
            weight[sum] = tweight * rate;
            value[sum] = tvalue * rate;
            s -= rate;
            rate *= 2;
        }
        if (s > 0) {
            sum ++;
            weight[sum] = tweight * s;
            value[sum] = tvalue * s;
        }
    }
    for (ll i = 1; i <= sum; i ++) {
        for (ll j = V; j >= weight[i]; j --) {
            dp[j] = max(dp[j - weight[i]] + value[i], dp[j]);
        }
    }
    cout << dp[V] << endl;
    return 0;
}
分组背包
#include <bits/stdc++.h>
using namespace std;

typedef long long lint;
lint n, m, grocnt = -1;
lint wei[1005];
lint val[1005];
lint group[1005];
lint dp[1005];

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> m >> n;
    for (int i = 1; i <= n; i ++) {
        cin >> wei[i] >> val[i] >> group[i];
        grocnt = max(grocnt, group[i]);
    }
    for (int i = 1; i <= grocnt; i ++) {
        for (int j = m; j >= 0; j --) {
            for (int k = 1; k <= n; k ++) {
                if (group[k] != i || j < wei[k]) continue;
                dp[j] = max(dp[j], dp[j - wei[k]] + val[k]);
            }
        }
    }
    cout << dp[m] << endl;
    return 0;
}
混合背包问题
// 混合背包问题(AcWing 7)
#include <iostream>
#include <cstring>
using namespace std;

typedef long long ll;
ll dp[1005];
ll weight[110004], value[110004], sum = 0;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    ll N, V;
    cin >> N >> V;
    for (ll i = 1; i <= N; i++) {
        ll tweight, tvalue, s;
        cin >> tweight >> tvalue >> s;
        if (s == 0) s = 1000;
        if (s == -1) s = 1;
        ll rate = 1;
        while (rate <= s) {
            sum ++;
            weight[sum] = tweight * rate;
            value[sum] = tvalue * rate;
            s -= rate;
            rate *= 2;
        }
        if (s > 0) {
            sum ++;
            weight[sum] = tweight * s;
            value[sum] = tvalue * s;
        }
    }
    for (ll i = 1; i <= sum; i ++) {
        for (ll j = V; j >= weight[i]; j --) {
            dp[j] = max(dp[j - weight[i]] + value[i], dp[j]);
        }
    }
    cout << dp[V] << endl;
    return 0;
}
最大子段和
cin >> n;
for (int i = 1; i <= n; i ++) {
	ll x;
	cin >> x;
	f[i] = max(f[i-1] + x, x);
}
ll ans = -1e18;
for (int i = 1; i <= n; i ++) {
	ans = max(ans, f[i]);
}
cout << ans << endl;
最长上升子序列(二分优化)
#include <bits/stdc++.h>
using namespace std;

int n = 0;
int a[1000006] = {};
int g[1000006] = {};
int len = 0;

int main() {
    cin >> n;
    for (int i = 1; i <= n; i ++) {
        cin >> a[i];
    }
    
    for (int i = 1; i <= n; i ++) {
        int pos = lower_bound(g + 1, g + len + 1, a[i]) - g;
        g[pos] = a[i];
        len = max(len, pos);
    }

    cout << len << endl;
    return 0;
}
最长不降子序列(二分优化)
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
ll n = 0;
ll arr[500005];
ll dp[500005];

ll my_lwb(ll le, ll x) {
	ll l = 1, r = le;
	while (l <= r) {
		ll mid = (l + r) >> 1;
		if (dp[mid] >= x) l = mid + 1;
		else r = mid - 1;
	}
	return l;
}

int main() {
	while (cin >> arr[++n]); n --;
	
	ll len = 0;
	for (ll i = 1; i <= n; i ++) {
		ll pos = my_lwb(len, arr[i]);
		dp[pos] = arr[i];
		len = max(len, pos);
	}
	cout << len << endl;
	
	return 0;
}
动态规划求回文子串
int f[2020][2020];
string s = "cicabadbd";
void huiwen() {
    int n = s.length();
    for (int i = 0; i < n; i ++) {
        f[i][i] = 1;
        if (i < n - 1 && s[i] == s[i + 1]) {
            f[i][i + 1] = 1;
        }
    }
    for (int l = 3; l <= n; l ++) { // 区间长度
        for (int i = 0; i + l - 1 < n; i ++) { // 区间左端点
            int j = i + l - 1; // 区间右端点
            if (s[i] == s[j] && f[i + 1][j - 1]) {
                f[i][j] = 1;
            }
        }
    }
}
破环成链
for (lint i = 1; i <= n; i ++) {
    arr[i + n] = arr[i];
}

lint ans = -1;
for (int i = 2; i < 2 * n; i ++) {
    for (int j = i - 1; i - j < n && j >= 1; j --) {
        for (int k = j; k < i; k ++) {
            ans = max(ans, dp[j][i]);
        }
    }
}
cout << ans << endl;
区间动态规划(小区间至大区间)
for (lint len = 2; len <= n; len ++) {
    for (lint i = 1; i <= n - len + 1; i ++) {
        lint j = i + len - 1;
    }
}
区间动态规划(大区间至小区间)
for (int l = 1; l <= n; l ++) {
    for (int r = n; r >= l; r --) {
        dp[l][r] = 0;
    }
}
最长公共子序列(无二分优化)
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
int dp[501][501];
int a[501], b[501];
int main() {
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++) cin >> a[i];
    for (int i = 1; i <= m; i++) cin >> b[i];
    for (int i = 1; i <= n; i ++) {
        for (int j = 1; j <= m; j ++) {
            if (a[i] == b[j]) {
                dp[i][j] = dp[i-1][j-1] + 1;
            } else {
                dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
            }
        }
    }
    cout << dp[n][m] << endl;
    return 0;
}
最长公共子序列(有二分优化)
#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 5;
int a[N], b[N], arr[N], f[N];

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int n = 0;
    cin >> n;
    for (int i = 1; i <= n; i ++) {
        cin >> a[i];
        arr[a[i]] = i;
    }
    for (int i = 1; i <= n; i ++) {
        cin >> b[i];
        f[i] = INT_MAX;
    }

    int len = 0;
    f[0] = 0;
    for (int i = 1; i <= n; i ++) {
        int l = 0, r = len, mid = -1;
        if (arr[b[i]] > f[len]) {
            len ++;
            f[len] = arr[b[i]];
        } else {
            while (l <= r) {
                mid = (l + r) >> 1;
                if (f[mid] == arr[b[i]]) break;
                else if (f[mid] > arr[b[i]])  r = mid - 1;
                else if (f[mid] < arr[b[i]]) l = mid + 1;
            }
            f[l] = min(arr[b[i]], f[l]);
        }
    }
    cout << len << endl;
    return 0;
}

图论

P4779 单源最短路径(标准版)
#include <iostream>
#include <cstring> // memset
#include <map>
#include <queue> 
#include <vector> // 小根堆 
using namespace std;

typedef pair<int, int> PII; // first: 距离,second: 节点编号

const int N = 1e5 + 10;
int n, m, s;

// h: head, w: weight边权,ne: next,dist: 距离,ver: 邻接表(链式前向星) 
int h[N], w[2 * N], ver[2 * N], ne[2 * N], cnt; 
int dist[N]; // s 点到所有点的最短路径
bool vis[N]; // 标记这个点是否已经出队 

// 添加一条边 
void add(int x, int y, int z) { // x -> y, 边权 z 
    ver[++cnt] = y;
    ne[cnt] = h[x];
    h[x] = cnt;
    w[cnt] = z;
}

void dijkstra(int s) { // 主算法 
    memset(dist, 0x3f, sizeof(dist)); // 将所有距离初始化为无穷大
    dist[s] = 0; // 起点到自己的距离为 0
    priority_queue<PII, vector<PII>, greater<PII> > heap; // 定义小根堆
    heap.push({0, s}); // s 点到 s 点距离为 0 
    
    while (heap.size()) {
        // 取出堆顶元素并弹出 
        PII t = heap.top();
        heap.pop();
        
        int x = t.second, d = t.first;
        
        if (vis[x]) continue; // 如果出过队,则不需要继续扩展
        vis[x] = 1; // 设置标记数组
        
        for (int i = h[x]; i; i = ne[i]) { // 扩展 
            int y = ver[i];
            if (dist[y] > d + w[i]) {
                dist[y] = d + w[i];
                heap.push({dist[y], y});
            }
        } 
    }
}

int main() {
    // 读入图 
    cin >> n >> m >> s;
    for (int i = 1; i <= m; i ++) { // 读入每条边 
        int x, y, z;
        cin >> x >> y >> z;
        add(x, y, z); // 添加这条边 
    }
    
    // 调用算法
    dijkstra(s);
    // 输出结果 
    for (int i = 1; i <= n; i ++) 
        cout << dist[i] << " ";
    cout << endl;
    
    return 0;
} 
最小生成树(Kruskal)
int n, m; // 点数(连通块个数),边数
struct edge { // edge 边
    int u, v, w;
} e[maxm];

int Find(int x);
void merge(int x, int y);
void kruskal() {
    sort(e + 1, e + m + 1); // 边权从小到大排序
    for (int i = 1; i <= m && n > 1; i ++) {
        auto [u,v,w] = e[i]; // 结构化绑定(C++17,考试支持)
        if (Find(u) != Find(v)) {
            merge(u, v);
            sum += w;
            n --;
        }
    }
}
最小生成树(Prim)
int G[maxn][maxn]; // 邻接矩阵

for (int i = 1; i <= n; i ++) {
    dis[i] = G[1][i];
}
used[1] = true;
for (int i = 1; i <= n - 1; i ++) {
    int minval = INT_MAX, minid = 0;
    for (int j = 1; j <= n; j ++) {
        if (!used[j] && dis[j] < minval) {
            minval = dis[j];
            minid = j;
        }
    }
    if (minval == INT_MAX) {
        cout << "orz\n";
        return 0;
    }
    used[minid] = 1;
    sum += minval;
    for (int j = 1; j <= n; j ++) {
        if (!used[j] && G[minid][j] < dis[j]) {
            dis[j] = G[minid][j];
        }
    }
}
B3644 拓扑排序(家谱树)
#include <bits/stdc++.h>
using namespace std;

int n;
vector<int> ver[105];
int ind[105];

int main() {
    cin >> n;
    for (int i = 1; i <= n; i ++) {
        int to;
        while (cin >> to) {
            if (to == 0) break;
            ver[i].push_back(to);
            ind[to] ++;
        }
    }
    
    priority_queue<int, vector<int>, greater<int> > q;
    for (int i = 1; i <= n; i ++) {
        if (ind[i] == 0) q.push(i);
    }
    
    while (!q.empty()) {
        int x = q.top();
        q.pop();
        cout << x << " ";
        for (int i = 0; i < ver[x].size(); i ++) {
            int y = ver[x][i];
            ind[y] --;
            if (ind[y] == 0) q.push(y);
        }
    }
    return 0;
}
P1113 拓扑排序(杂务)
void tuopu_sort() {
    queue<int> q;
    for (int i = 1; i <= n; i ++) {
        if (ind[i] == 0) {
            q.push(i);
            f[i] = len[i];
        }
    }
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        for (auto v: G[u]) {
            ind[v] --;
            if (ind[v] == 0) {
                q.push(v);
            }
            f[v] = max(f[v], f[u] + len[v]);
        }
    }
}
洪水填充 flood fill
#include <iostream>
#include <map>
#include <queue>
using namespace std;

typedef pair<int, int> PII;
char image[10][10];
int cx[] = {0, 0, 1, -1};
int cy[] = {1, -1, 0, 0};

bool is_valid(PII pt, int pcol, int ncol) {
    int x = pt.first, y = pt.second;
    return (1 <= x && x <= 8 && 1 <= y && y <= 8 && image[x][y] == pcol && image[x][y] != ncol);
}

void flood_fill(PII cur, int ncol) {
    queue<PII> Q;
    Q.push(cur);

    int pcol = image[cur.first][cur.second];
    image[cur.first][cur.second] = ncol;

    while (!Q.empty()) {
        PII pt = Q.front();
        Q.pop();

        for (int ch = 0; ch < 4; ch ++) {
            PII npt = {pt.first + cx[ch], pt.second + cy[ch]};
            if (is_valid(npt, pcol, ncol)) {
                image[npt.first][npt.second] = ncol;
                Q.push(npt);
            }
        }
    }
}

int main() {
    char new_color;
    for (int i = 1; i <= 8; i ++) {
        for (int j = 1; j <= 8; j ++) {
            cin >> new_color;
            image[i][j] = new_color;
        }
    }

    PII cur = make_pair(4, 4);
    cin >> new_color;

    flood_fill(cur, new_color);

    for (int i = 1; i <= 8; i ++) {
        for (int j = 1; j <= 8; j ++) {
            cout << image[i][j] << " ";
        }
        cout << endl;
    }
    return 0;
}

/*
Input:
gggggggg
ggggggrr
grrggrgg
gbbbbrgr
gggbbrgr
gggbbbbr
gggggbgg
gggggbbg
y

Output:
g g g g g g g g
g g g g g g r r
g r r g g r g g
g y y y y r g r
g g g y y r g r
g g g y y y y r
g g g g g y g g
g g g g g y y g
*/
Dijkstra + 堆优化(稀疏图)
struct node {
    int to, dis;
    bool operator < (const node &rhs) const {
        return dis > rhs.dis;
    }
};

int dis[maxn];
bool vis[maxn];
vector<int> G[maxn];
void dijkstra() {
    fill(dis, dis + n + 1, INT_MAX);
    dis[s] = 0;
    priority_queue<node> q;
    q.push({s, 0});
    while (!q.empty()) {
        auto [u, d] = q.top();
        q.pop();
        if (vis[u]) continue;
        vis[u] = true;
        for (auto v: G[u]) {
            auto [to, d] = v;
            if (dis[to] > dis[u] + d) {
                dis[to] = dis[u] + d;
                q.push({to, dis[to]});
            }
        }
    }
}
Bellman-ford 算法求单源多汇最短路
// 太戈编程 589 武林大会
// 多源单汇最短路 -> 反边 -> 单源多汇最短路
// Bellman-ford 算法模板 
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
ll n, m;
ll peo_num[1005];
struct Edge {
	ll u, v, w;
} arr[4005]; // 无向图边表加倍! 

ll dis[1005];
void Bellman_ford() {
	memset(dis, 0x3f, sizeof(dis));
	dis[1] = 0;
	for (int ti = 1; ti < n; ti ++) { // 扫描需要执行 n-1 次! 
		for (int i = 1; i <= 2 * m; i ++) {
			if (dis[arr[i].u] != 0x3f3f3f3f) {
				dis[arr[i].v] = min(dis[arr[i].v], dis[arr[i].u] + arr[i].w);
			}
		}		
	}
}

int main() {
	cin >> n;
	for (int i = 1; i <= n; i ++) cin >> peo_num[i];
	cin >> m;
	for (int i = 1; i <= m; i ++) {
		cin >> arr[i*2-1].u >> arr[i*2-1].v >> arr[i*2-1].w;
		arr[i*2].u = arr[i*2-1].v;
		arr[i*2].v = arr[i*2-1].u;
		arr[i*2].w = arr[i*2-1].w;
	}
	
	Bellman_ford();
	
	ll ans = 0;
	for (int i = 2; i <= n; i ++) {
		if (dis[i] >= 0x3f3f3f3f -100) continue;
		ans += dis[i] * peo_num[i];
	}
	cout << ans << endl;
	return 0;
} 
SPFA
void spfa() {
    fill(dis, dis + n + 1, INT_MAX);
    queue<int> q;
    q.push(s);
    dis[s] = 0;
    inq[s] = 1;
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        for (auto [v, w]: G[u]) {
            if (dis[v] > dis[u] + w) {
                dis[v] = dis[u] + w;
                if (!inq[v]) {
                    inq[v] = true;
                    q.push(v);
                }
            }
        }
    }
}
SPFA 判断负环
void negative_circle() {
    fill(dis, dis + n + 1, INT_MAX);
    queue<int> q;
    q.push(s);
    dis[1] = len[1] = 0;
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        vis[u] = false;
        for (auto [v, d]: G[u]) {
            if (dis[u] + d < dis[v]) {
                dis[v] = dis[u] + d;
                len[v] = len[u] + 1;
                if (len[v] == n) {
                    puts("YES");
                    return;
                }
                if (!vis[v]) {
                    vis[v] = 1;
                    q.push(v);
                }
            }
        }
    }
    puts("NO");
}
Floyd 算法(多源最短路)
for (int k = 1; k <= n; k ++) {
    f[k][k] = 0;
    for (int i = 1; i <= n; i ++) {
        for (int j = 1; j <= n; j ++) {
            f[i][j] = min(f[i][j], f[i][k] + f[k][j]);
        }
    }
}

数学

同余方程求特解(exgcd)
int exgcd(int a, int b, int &x, int &y) { // x, y 传引用
    if (!b) {
        x = 1;
        y = 0;
        return a;
    }
    int d = exgcd(b, a % b, x, y);
    int t = x, x = y;
    y = t - (a / b) * y;
    return d;
}
埃氏筛质数
int n;
bool pri[100005] = {};
void Init() {
    memset(pri, 1, sizeof pri);
    pri[0] = pri[1] = false;
    for (int i = 2; i < n; i ++) {
        if (!pri[i] || (long long) i * i >= n)
            continue;
        for (int j = i * i; j <= n; j += i)
            pri[j] = false;
    }
}
线性筛质数
ll n = 0, q = 0;
bool is_prime[100000010];
ll prime[10000010];
ll pcnt = 0;
void shai() {
    memset(is_prime, 1, sizeof(is_prime));
    is_prime[0] = is_prime[1] = 0;
    
    for (int i = 2; i <= n; i ++) {
        if (is_prime[i]) {
            pcnt ++;
            prime[pcnt] = i;
        }
        
        for (int j = 1; j <= pcnt and i * prime[j] <= n; j ++) {
            is_prime[i * prime[j]] = 0;
            if (i % prime[j] == 0) {
                break;
            }
        }
    }
    return;
}
线性筛求最小质因子
typedef long long ll;
const ll N = 2e7 + 10;
ll pcnt = 0;
int pri[N], ispri[N], minpri[N], f[N];

void shai() {
	for (int i = 2; i <= maxn; i ++) {
		if (!ispri[i]) {
			pcnt ++;
			pri[pcnt] = i;
			minpri[i] = i;
		}
		for (int j = 1; j <= pcnt && pri[j] * i <= N; j ++) {
			ispri[i * pri[j]] = 1;
			minpri[i * pri[j]] = pri[j];
			if (i % pri[j] == 0) break;
		}
	}
}
高精度加法
const int N = 10500;
int na[N] = {0}, nb[N] = {0}, ans[N + 1] = {0};
string big_add(string a, string b) {
    string sum;
    memset(na, 0, sizeof(na));
    memset(nb, 0, sizeof(nb));
    memset(ans, 0, sizeof(ans));
    for (int i = a.size(); i > 0; i --) na[i] = a[a.size() - i] - '0';
    for (int i = b.size(); i > 0; i --) nb[i] = b[b.size() - i] - '0';

    int maxlen = max(a.size(), b.size());
    for (int i = 1; i <= maxlen; i ++) { // 模拟竖式加法
        ans[i + 1] = (ans[i] + na[i] + nb[i]) / 10;
        ans[i] = (ans[i] + na[i] + nb[i]) % 10;
    }

    if (ans[maxlen + 1] != 0) sum += "1"; // 防止最高位进位
    for (int i = maxlen; i > 0; i --) {
        sum += ans[i] + '0';
    }
    return sum;
}
高精度减法
const int N = 10500;
int na[N] = {0}, nb[N] = {0}, ans[N + 1] = {0};
string big_minus(string a, string b) {
    string diff;
    memset(na, 0, sizeof(na));
    memset(nb, 0, sizeof(nb));
    memset(ans, 0, sizeof(ans));
    if ((a < b && a.size()) || b.size() > a.size()) { // 特判 b > a
        return "-" + big_minus(b, a);
    }

    for (int i = a.size(); i > 0; i --) na[i] = a[a.size() - i] - '0';
    for (int i = b.size(); i > 0; i --) nb[i] = b[b.size() - i] - '0';   

    int maxlen = max(a.size(), b.size());

    for (int i = 1; i <= maxlen; i ++) {
        if (na[i] < nb[i]) { // 模拟退位
            na[i + 1] --;
            na[i] += 10;
        }
        ans[i] = na[i] - nb[i];
    }
    while (ans[maxlen] == 0) maxlen --;
    if (maxlen < 1) return "0";
    for (int i = maxlen; i > 0; i --) diff += ans[i] + '0';
    return diff;
}
高精度乘法
const int N = 10500;
int na[N] = {0}, nb[N] = {0}, ans[N + 1] = {0};
string big_times(string a, string b) {
    string mul;
    memset(na, 0, sizeof(na));
    memset(nb, 0, sizeof(nb));
    memset(ans, 0, sizeof(ans));
    for (int i = 0; i < a.size(); i ++) na[i + 1] = a[a.size() - i - 1] - '0';
    for (int i = 0; i < b.size(); i ++) nb[i + 1] = b[b.size() - i - 1] - '0';   

    int maxlen = a.size() + b.size();

    for (int i = 1; i <= a.size(); i ++) {
        for (int j = 1; j <= b.size(); j ++) {
            ans[i + j - 1] += na[i] * nb[j];
        }
    }    

    for (int i = 1; i <= maxlen; i ++) {
        ans[i + 1] += ans[i] / 10;
        ans[i] %= 10;
    }

    while (ans[maxlen] == 0) maxlen --;
    for (int i = max(1, maxlen); i >= 1; i --) {
        mul += ans[i] + '0';
    }
    return mul;
}
高精度除法(高精除低精)
string big_div(string a, string b) {
    string div;
    memset(na, 0, sizeof(na));
    memset(nb, 0, sizeof(nb));
    memset(ans, 0, sizeof(ans));  
    for (int i = 1; i <= a.size(); i ++) na[i] = a[i - 1] - '0';
    long long left = 0;
    long long numb = 0;
    for (int i = 0; i < b.size(); i ++) {
        numb += (b[i] - '0') * pow(10, b.size() - i - 1);
    }
    for (int i = 1; i <= a.size(); i ++) {
        ans[i] = (left * 10 + na[i]) / numb;
        left = (left * 10 + na[i]) % numb;
    }
    long long first_ok = 1;
    while (ans[first_ok] == 0 && first_ok < a.size()) first_ok ++;
    for (int i = first_ok; i <= a.size(); i ++) div += (ans[i] + '0');
    return div;
}
高精度取模(高精模低精)
long long big_mod(string a, string b) {
    string div;
    memset(na, 0, sizeof(na));
    memset(nb, 0, sizeof(nb));
    memset(ans, 0, sizeof(ans));  
    for (int i = 1; i <= a.size(); i ++) na[i] = a[i - 1] - '0';
    long long left = 0;
    long long numb = 0;
    for (int i = 0; i < b.size(); i ++) {
        numb += (b[i] - '0') * pow(10, b.size() - i - 1);
    }
    for (int i = 1; i <= a.size(); i ++) {
        ans[i] = (left * 10 + na[i]) / numb;
        left = (left * 10 + na[i]) % numb;
    }
    return left;
}
字符数组旋转九十度
char s[130][130];
void rotate(int &a, int &b) {
    char tmp[130][130];
    for (int i = 1; i <= a; i ++) {
        for (int j = 1; j <= b; j ++) {
            tmp[i][j] = s[i][j];
        }
    }

    for (int i = 1; i <= a; i ++) {
        for (int j = 1; j <= b; j ++) {
            s[j][a - i + 1] = tmp[i][j];
        }
    }
    swap(a, b);
}
二元一次不定方程
#include <bits/stdc++.h>
using namespace std;

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

int main() {
    long long T;
    cin >> T;
    while (T--) {
        long long a, b, c, d, x, y;
        cin >> a >> b >> c;
        d = exgcd(a, b, x, y);
        if (c % d != 0) cout << -1 << endl;
        else {
            long long mix = (x%(b/d)+b/d)%(b/d)*(long long)(c/d)%(b/d);
            if (mix == 0) mix = b / d;
            long long miy = (y%(a/d)+a/d)%(a/d)*(long long)(c/d)%(a/d);
            if (miy == 0) miy = a / d;
            if (miy >= (c + b - 1) / b || mix >= (c + a - 1) / a) {
                cout << mix << " " << miy << endl;
            } else {
                long long mxx = (c - miy * b) / a;
                long long mxy = (c - mix * a) / b;
                cout << (mxx-mix)/(b/d)+1 << " " << mix << " " << miy << " " << mxx << " " << mxy << endl;
            }
        }
    }
    return 0;
}
求特定组合数(懒标记)
long long c1(long long a, long long b) {
    long long ans = 1;
    long long lazytag = 1;
    for (long long i = a, j = 2; ; i --, j ++) {
        bool flag = false;
        if (i >= a - b + 1) {
            ans *= i;
            flag = true;
        }
        if (j <= b) {
            if (ans % lazytag == 0) {
                ans /= lazytag;
                lazytag = 1;
            }

            if (ans % j == 0) {
                ans /= j;
            } else {
                lazytag *= j;
            }

            flag = true;
        }
        if (!flag) break;
    }
    ans /= lazytag;
    return ans;
}
辗转相除求 gcd
long long gcd(long long a, long long b) {
    if (b == 0) return a;
    else return gcd(b, a % b);
}
预处理组合数
int c[2005][2005] = {};
c[1][1] = 1;
for (int i = 1; i <= 2000; i ++) {
    c[i][0] = 1;
    c[i][i] = 1;
}
for (int i = 2; i <= 2000; i ++) {
    for (int j = 1; j < i; j ++) {
        c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % k;
    }
}
快速幂+取模运算
ll quick_pow(ll a, ll b, ll p) {
    ll ans = 1 % p;
    while (b) {
        if (b & 1) {
            ans = (ll)ans * a % p;
        }
        a = (ll)a * a % p;
        b >>= 1;
    }
    return ans;
}
计算特定区域内某因子个数
ll cntx(ll x) {
    ll l = a, r = b;
    ll ans = -1;
    while (l != r) {
        ans ++;
        l /= x;
        r /= x;
    }
    return ans;
}

计算几何

离散化扫描(扫描线)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;

typedef long long ll;

const int N = 1e5 + 10;

ll n, m;
struct Node { // 记录矩形 
    ll x, y1, y2; // 左上点、右边界
    ll k; // 1 or -1:左边界(起点)     右边界(终点)
    bool operator < (const Node &t) const {
        return x < t.x; // sort 按照 x 升序排序 
    } 
} rect[N * 2]; // rectangle   一个矩形左右边界 两倍空间 

// 用线段树来维护 y 轴方向的区间信息
struct Tree {
    ll l, r;
    ll cnt; // 记录覆盖次数
    ll len; // 覆盖长度(原始为浮点数)(y 轴方向) 
} t[N * 8]; // 2 * 4 = 8 

vector<ll> ys; // y 原始值过大且为浮点数,离散化 

int find(ll y) { // 二分查找 离散化对应的值 
    // 注意:获取的下标从 0 开始 
    return lower_bound(ys.begin(), ys.end(), y) - ys.begin(); // 迭代器减法获取下标 
}

void build(ll u, ll l, ll r) {
    t[u].l = l, t[u].r = r;
    if (l == r) { // 叶子节点 
        t[u].cnt = t[u].len = 0;
        return;
    }

    ll mid = (l + r) >> 1;
    build(u * 2, l, mid);
    build(u * 2 + 1, mid + 1, r);
    // 不需要 push_up 
}

void pushup(ll u) {
    // cnt 不为 0,被完全覆盖,区间有效,长度为离散化对应的原始值 
    if (t[u].cnt) t[u].len = ys[t[u].r + 1] - ys[t[u].l];
    else if (t[u].l == t[u].r) t[u].len = 0; // 元区间(最小划分区间),未被覆盖,长度为 0 
    else t[u].len = t[u * 2].len + t[u * 2 + 1].len; // 区间部分覆盖,累加左右子区间的覆盖长度 
}

void modify(ll u, ll l, ll r, ll k) {
    if (l <= t[u].l && r >= t[u].r) {
        t[u].cnt += k;
        pushup(u);
        return;
    }

    // 不需要 push_down
    // 因为操作区间一定是成对出现的,只需要维护到父亲节点即可 
    // 查询的时候,也是到父亲节点就会返回

    ll mid = (t[u].l + t[u].r) >> 1;
    if (l <= mid) modify(u * 2, l, r, k); // 更新左子树 
    if (r > mid) modify(u * 2 + 1, l, r, k); // 更新右子树
    pushup(u); // 将节点信息传递给父亲 
}

int main() {
//  freopen("atlantis.in", "r", stdin);
//  freopen("atlantis.out", "w", stdout);
    scanf("%lld", &n);
    ys.clear(); // 多组数据,清空 vector 
    for (int i = 0; i < n; i ++) {
        ll x1, y1, x2, y2;
        scanf("%lld%lld%lld%lld", &x1, &y1, &x2, &y2);
        ys.push_back(y1);
        ys.push_back(y2);

        rect[i * 2] = {x1, y1, y2, 1}; // 起点边,偶数 
        rect[i * 2 + 1] = {x2, y1, y2, -1}; // 终点边,奇数 
    }
    // 对 vector 进行离散化
    sort(ys.begin(), ys.end());
    ys.erase(unique(ys.begin(), ys.end()), ys.end()); // 去重 + 删除重复元素 

    m = ys.size(); // 存储 vector 大小 
    build(1, 0, m - 2); // m 条边对应 m - 1 个区间

    sort(rect, rect + n * 2); // 对 x 进行升序排序,准备从左往右扫描

    // 扫描开始 
    ll res = 0;
    for (int i = 0; i < n * 2;) { // i 在函数内进行控制 
        int j = i;
        while (j < n * 2 && rect[j].x == rect[i].x) {
            j ++;
            // 扫描所有 x 重复的边(在同一刻度上),j 表示下一条边 
        } 
        if (i) { // 第一条边不需要进行计算 
            res += t[1].len * (rect[i].x - rect[i - 1].x);
            // 根节点记录的是扫描线总长度 
        }
        while (i < j) {
            // 上边界对应的区间不在统计范围内(M 条线 => M - 1 个区间) 
            modify(1, find(rect[i].y1), find(rect[i].y2) - 1, rect[i].k);
            i ++;
        }
    } 

    cout << res << endl;
    return 0;
}

数据结构

队列
#include <bits/stdc++.h>
using namespace std;

int main() {
    int N = 0;
    cin >> N;
    queue <int> q;
    while (N--) {
        int op = 0;
        cin >> op;

        if (op == 1) {
            int x = 0;
            cin >> x;
            q.push(x);
        } else if (op == 2) {
            if (q.size() == 0) {
                cout << "ERR_CANNOT_POP" << endl;
            } else {
                q.pop();
            }
        } else if (op == 3) {
            if (q.size() == 0) {
                cout << "ERR_CANNOT_QUERY" << endl;
            } else {
                cout << q.front() << endl;
            }
        } else {
            cout << q.size() << endl;
        }
    }
    return 0;
}
#include <bits/stdc++.h>
using namespace std;

int main() {
    int T;
    cin >> T;
    while (T--) {
        vector<unsigned long long> st;
        int n = 0;
        cin >> n;
        for (int i = 1; i <= n; i ++) {
            string op;
            unsigned long long x;
            cin >> op;
            if (op == "push") {
                cin >> x;
                st.push_back(x);
            } else if (op == "query") {
                if (st.size() != 0) {
                    cout << st.back() << endl;
                } else {
                    cout << "Anguei!" << endl;
                }
            } else if (op == "size") {
                cout << st.size() << endl;
            } else if (op == "pop") {
                if (st.size() != 0) {
                    st.pop_back();
                } else {
                    cout << "Empty" << endl;
                }
            }
        }
    }
    return 0;
}
并查集
int f[maxn];

int find(int x) {
    if (f[x] == x) return x;
    else return f[f[x]] = find(f[x]);
}

void merge(int x, int y) {
    int r1 = find(x);
    int r2 = find(y);
    f[r2] = r1;
}

bool isCon(int x, int y) {
    return find(x) == find(y);
}

void init() {
    for (int i = 1; i <= n; i ++) {
        f[i] = i;
    }
}
并查集(按秩合并)
int fa[maxn];
int sz[maxn];

int find2(int x) {
    if (fa[x] == x) return x;
    else return find2(fa[x]); // 按秩合并一般不进行路径压缩
}

void merge2(int x, int y) {
    x = find2(x);
    y = find2(y);
    if (x != y) {
        if (sz[x] < sz[y]) swap(x, y);
        fa[y] = x;
        sz[x] += sz[y]; 
    }
}
P3374 树状数组1
#include <bits/stdc++.h>
using namespace std;

const int N = 5e5 + 10;
int n, m;
int a[N], t[N];

int lowbit(int x) {
    return x & (-x);
} 

// 单点修改 
void add(int x, int y) { // 在 x 的位置加上 y 
    a[x] += y;
    while (x <= n) {
        t[x] += y;
        x += lowbit(x);
    }
}

// 查询前缀和
int ask(int x) {
    int ans = 0;
    while (x) {
        ans += t[x];
        x -= lowbit(x); 
    }
    return ans;
} 

int main() {
    cin >> n >> m;
    for (int i = 1; i <= n; i ++) { // 初始化 
        int v;
        cin >> v;
        add(i, v);
    }
    
    while (m --) {
        int p, x, y;
        cin >> p >> x >> y;
        if (p == 1) {
            add(x, y);
        } else {
            cout << ask(y) - ask(x - 1) << endl;
        }
    }
    return 0;
}
P3368 树状数组2
// 树状数组:区间操作,单点查询 -- 差分
// 用树状数组记录差分序列,查询时输出差分序列的前缀和 + 原序列初始值 
#include <iostream>
using namespace std;

const int N = 5e5 + 10;
int n, m;
int a[N], t[N];

int lowbit(int x) {
    return x & (-x);
}

int add(int x, int y) {
    while (x <= n) {
        t[x] += y;
        x += lowbit(x);
    }
}

int ask(int x) {
    int ans = 0;
    while (x) {
        ans += t[x];
        x -= lowbit(x);
    }
    return ans;
}

int main() {
    cin >> n >> m;
    for (int i = 1; i <= n; i ++) {
        cin >> a[i];
    }
    
    while (m --) {
        int p, x, y, k;
        cin >> p;
        if (p == 1) {
            cin >> x >> y >> k; // [x, y] 差分 --> x, y + 1 
            add(x, k);
            add(y + 1, -k);
        } else {
            cin >> x;
            cout << ask(x) + a[x] << endl; // 加上原始值 
        }
    }
    return 0;
}
P3372 线段树1
#include <iostream>
using namespace std;

const int N = 1e5 + 10;

struct SegmentTree{
    int l, r;
    long long sum, add;
    #define l(x) t[x].l
    #define r(x) t[x].r
    #define sum(x) t[x].sum
    #define add(x) t[x].add
} t[N * 4];

int a[N], n, m;

// 建树
void build(int p, int l, int r) {
    l(p) = l, r(p) = r;
    if (l == r) {
        sum(p) = a[l];
        return;
    }
    int mid = (l + r) >> 1;
    build(p * 2, l, mid);
    build(p * 2 + 1, mid + 1, r);
    sum(p) = sum(p * 2) + sum(p * 2 + 1); // push_up
} 

// 标记下传
void push_down(int p) {
    if (add(p)) {
        sum(p * 2) += add(p) * (r(p * 2) - l(p * 2) + 1);
        sum(p * 2 + 1) += add(p) * (r(p * 2 + 1) - l(p * 2 + 1) + 1);
        add(p * 2) += add(p); // 标记左右儿子 
        add(p * 2 + 1) += add(p);
        add(p) = 0; // 清除父节点标记 
    }
} 

void motify(int p, int l, int r, long long v) {
    if (l <= l(p) && r >= r(p)) {
        sum(p) += 1ll * v * (r(p) - l(p) + 1); // 更新当前节点的值
        add(p) += v;
        return;
    }
    push_down(p); // 下传标记
    int mid = (l(p) + r(p)) >> 1;
    if(l <= mid) motify(p * 2, l, r, v);
    if (r > mid) motify(p * 2 + 1, l, r, v);
    sum(p) = sum(p * 2) + sum(p * 2 + 1); // push_up
}

long long query(int p, int l, int r) {
    if (l <= l(p) and r >= r(p)) return sum(p);
    push_down(p); // 下传标记!
    int mid = (l(p) + r(p)) >> 1; 
    long long val = 0;
    if (l <= mid) val += query(p * 2, l, r);
    if (r > mid) val += query(p * 2 + 1, l, r); 
    return val;
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i ++) scanf("%d", &a[i]);
    build(1, 1, n);
    while (m --) {
        int op, l, r;
        scanf("%d%d%d", &op, &l, &r);
        if (op == 1) {
            long long v;
            scanf("%lld", &v);
            motify(1, l, r, v);
        } else {
            printf("%lld\n", query(1, l, r));
        }
    }
    return 0;
}
P3373 线段树2
#include <iostream>
using namespace std;

typedef long long ll;
const int N = 1e5 + 10;

struct SegmentTree{
    ll l, r;
    ll sum, add, mul;
    #define l(x) t[x].l
    #define r(x) t[x].r
    #define sum(x) t[x].sum
    #define add(x) t[x].add
    #define mul(x) t[x].mul
} t[N * 4];

ll a[N], n, m, MOD;

// 建树
void build(ll p, ll l, ll r) {
    l(p) = l, r(p) = r, mul(p) = 1;
    if (l == r) {
        sum(p) = a[l];
        return;
    }
    ll mid = (l + r) >> 1;
    build(p * 2, l, mid);
    build(p * 2 + 1, mid + 1, r);
    sum(p) = 1ll * (sum(p * 2) + sum(p * 2 + 1)) % MOD; // push_up
} 

// 标记下传
void push_down(ll p) {
    if (add(p) || mul(p) != 1) {
        // 更新左子节点 sum 信息 (值 * 倍数 + 值 * 区间长度) 
        sum(p*2) = (sum(p*2) * mul(p) + add(p) * (r(p*2) - l(p*2) + 1)) % MOD;
        // 右
        sum(p*2+1) = (sum(p*2+1) * mul(p) + add(p) * (r(p*2+1) - l(p*2+1) + 1)) % MOD; 
        
        // 标记
        mul(p*2) = mul(p*2) * mul(p) % MOD;
        mul(p*2+1) = mul(p*2+1) * mul(p) % MOD;
        
        add(p*2) = (add(p*2) * mul(p) + add(p)) % MOD;
        add(p*2+1) = (add(p*2+1) * mul(p) + add(p)) % MOD;
        
        mul(p) = 1;
        add(p) = 0;
    }
} 

// 区间加法 
void motify_add(ll p, ll l, ll r, ll v) {
    if (l <= l(p) && r >= r(p)) {
        sum(p) = (sum(p) + v * (r(p) - l(p) + 1)) % MOD; // 更新当前节点的值
        add(p) = (add(p) + v) % MOD;
        return;
    }
    push_down(p); // 下传标记
    ll mid = (l(p) + r(p)) >> 1;
    if(l <= mid) motify_add(p * 2, l, r, v);
    if (r > mid) motify_add(p * 2 + 1, l, r, v);
    sum(p) = (sum(p * 2) + sum(p * 2 + 1)) % MOD; // push_up
}

// 区间乘法
void motify_mul(ll p, ll l, ll r, ll v) {
    if (l <= l(p) && r >= r(p)) {
        sum(p) = sum(p) * v % MOD;
        mul(p) = mul(p) * v % MOD;
        add(p) = add(p) * v % MOD; // 乘法会影响已有的加法! 
        return;
    }
    push_down(p); // 下传标记
    ll mid = (l(p) + r(p)) >> 1;
    if(l <= mid) motify_mul(p * 2, l, r, v);
    if (r > mid) motify_mul(p * 2 + 1, l, r, v);
    sum(p) = (sum(p * 2) + sum(p * 2 + 1)) % MOD; // push_up
} 

ll query(ll p, ll l, ll r) {
    if (l <= l(p) and r >= r(p)) return sum(p);
    push_down(p); // 下传标记!
    ll mid = (l(p) + r(p)) >> 1; 
    ll val = 0;
    if (l <= mid) val = (val + query(p * 2, l, r)) % MOD;
    if (r > mid) val = (val + query(p * 2 + 1, l, r)) % MOD; 
    return val;
}

int main() {
    scanf("%lld%lld%lld", &n, &m, &MOD);
    for (int i = 1; i <= n; i ++) scanf("%lld", &a[i]);
    build(1, 1, n);
    while (m --) {
        ll op, l, r;
        scanf("%lld%lld%lld", &op, &l, &r);
        if (op == 1) {
            ll v;
            scanf("%lld", &v);
            motify_mul(1, l, r, v);
        } else if (op == 3) {
            printf("%lld\n", query(1, l, r));
        } else if (op == 2) {
            ll v;
            scanf("%lld", &v);
            motify_add(1, l, r, v);            
        }
    }
    return 0;
}

字符串

KMP 字符串匹配
#include <iostream>
#include <cstring>
using namespace std;

char a[1000006], b[1000006];
int n, m;
int ne[1000006], f[1000006];

void get_ne() {
    int j = 0;
    for (int i = 2; i <= n; i ++) {
        while (j > 0 and a[i] != a[j + 1]) j = ne[j];
        if (a[i] == a[j + 1]) j ++;
        ne[i] = j;
    }
}

void get_f() {
    int j = 0;
    for (int i = 1; i <= m; i ++) {
        while (j > 0 and (b[i] != a[j + 1] or j == n)) j = ne[j];
        if (b[i] == a[j + 1]) j ++;
        f[i] = j;
        if (f[i] == n)
            cout << i - n + 1 << endl;
    }
}

int main() {
    cin >> (b + 1) >> (a + 1);
    n = strlen(a + 1);
    m = strlen(b + 1);
    get_ne();
    get_f();
    for (int i = 1; i <= n; i ++) {
        cout << ne[i] << " ";
    }
    cout << endl;
    return 0;
}
字符串哈希
// P3370 字符串哈希 
#include <bits/stdc++.h>
using namespace std;

typedef unsigned long long ull;
ull base = 131; // 经验值,131进制不容易发生冲突(13331也是)
ull a[10010]; // 哈希数组 
string s; // 字符串数组 
ull n, ans = 1;
ull prime = 233317; // 处理冲突的方法:在哈希值上不断加上一个大质数直到新位置未被占用
ull mod = 212370440130137957ull;

ull hashe(string s) {
	ull ans = 0;
	for (char c: s) {
		ans = (ans * base + ull(c)) % mod + prime;
	}
	return ans;
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	cin >> n;
	for (int i = 1; i <= n; i ++) {
		cin >> s;
		a[i] = hashe(s);
	}
	
	sort(a + 1, a + n + 1);
	for (int i = 1; i < n; i ++) {
		if (a[i] != a[i + 1]) ans ++;
	}
	cout << ans;
	return 0;
}
posted @ 2023-07-27 09:25  SuperUser777  阅读(498)  评论(0)    收藏  举报