数据类型及范围

bool	1 个字节	0 或 1

char	1 个字节	-128 到 127 或者 0 到 255

unsigned char	1 个字节	0 到 255

signed char	1 个字节	-128 到 127

int	4 个字节	-2147483648 到 2147483647

unsigned int	4 个字节	0 到 4294967295

signed int	4 个字节	-2147483648 到 2147483647

short int	2 个字节	-32768 到 32767

unsigned short int	2 个字节	0 到 65,535

signed short int	2 个字节	-32768 到 32767

long int	8 个字节	-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807

signed long int	8 个字节	-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807

unsigned long int	8 个字节	0 到 18,446,744,073,709,551,615

float	4 个字节	精度型占4个字节(32位)内存空间,+/- 3.4e +/- 38 (~7 个数字)

double	8 个字节	双精度型占8 个字节(64位)内存空间,+/- 1.7e +/- 308 (~15 个数字)

long double	16 个字节	长双精度型 16 个字节(128位)内存空间,可提供18-19位有效数字。

wchar_t	2 或 4 个字节	1 个宽字符

数学函数

abs(a)    a的绝对值
pow(x, y)    x的y次方
sqrt(a)    a的平方根
floor(a)    向下取整
ceil(a)    向上取整
round(a)    四舍五入

格式控制符

char ---- %c
int ---- %d
long long ---- %lld
float ---- %f    (默认6位)
double ---- %lf    (默认6位)
float ---- %._(小数位数)f
double ---- %._(小数位数)lf

排序

冒泡

void bubbleSort()
{
    bool f = 0;

    for (int i = 0; i < n - 1; i++)
    {
        f = 0;
        for (int j = 0; j < n - 1 - i; j++)
        {
            if (a[j] > a[j + 1])
            {
                swap(a[j + 1], a[j]);
                f = 1;
            }
        }

        if (!f)
        {
            return;
        }
    }
}

选择

void selectSort()
{
    int mi, t;
    for (int i = 0; i < n - 1; i++)
    {
        mi = i;
        for (int j = i + 1; j < n; j++)
        {
            if (a[j] < a[mi])
            {
                mi = j;
            }
        }
        if (mi != i)
        {
            t = a[mi];
            a[mi] = a[i];
            a[i] = t;
        }
    }
}

插入

void insertSort()
{
    int i, j, t;
    for (i = 1; i < n; i++)
    {
        t = a[i];
        for (j = i; j > 0 && a[j - 1] > t; j--)
            a[j] = a[j - 1];
        a[j] = t;
    }
}

归并

int a[500002];
int tmp[500002];

void merge(int l, int m, int r)
{
    int i = l, j = m + 1, k = l;
    while (i <= m && j <= r)
    {
        if (a[i] <= a[j])
            tmp[k++] = a[i++];
        else
            tmp[k++] = a[j++];
    }
    while (i <= m)
        tmp[k++] = a[i++];
    while (j <= r)
        tmp[k++] = a[j++];
    for (i = l; i <= r; i++)
        a[i] = tmp[i];
}

void merge_sort(int l, int r)
{
    if (l == r)
        return;
    int m = (l + r) / 2;
    merge_sort(l, m);
    merge_sort(m + 1, r);
    merge(l, m, r);
}

快速

void quickSort(int a[], int l, int r)
{
    int i, j, t, p;
    if (l > r)
        return;
    p = a[l];
    i = l;
    j = r;
    while (i != j)
    {
        while (a[j] >= p && i < j)
            j--;
        while (a[i] <= p && i < j)
            i++;
        if (i < j)
        {
            t = a[i];
            a[i] = a[j];
            a[j] = t;
        }
    }
    a[l] = a[i];
    a[i] = p;
    quickSort(a, l, i - 1);
    quickSort(a, i + 1, r);
}

二分查找模板

int binary_search()
{
    int l = 0, r = n - 1;
    while (l <= r)
    {
        int mid = l + (r - l) / 2;
        if (a[mid] < tar)
        {
            l = mid + 1;
        }
        else if (a[mid] > tar)
        {
            r = mid - 1;
        }
        else if (a[mid] == tar)
        {
            return mid;
        }
    }
    return -1;
}

左值查找模板

int left_bound()
{
    int l = 0, r = n - 1;
    while (l <= r)
    {
        int mid = l + (r - l) / 2;
        if (a[mid] < tar)
        {
            l = mid + 1;
        }
        else if (a[mid] > tar)
        {
            r = mid - 1;
        }
        else if (a[mid] == tar)
        {
            r = mid - 1;
        }
    }
    if (l >= n || a[l] != tar)
        return -1;
    return l;
}

右值查找模板

int right_bound()
{
    int l = 0, r = n - 1;
    while (l <= r)
    {
        int mid = l + (r - l) / 2;
        if (a[mid] < tar)
        {
            l = mid + 1;
        }
        else if (a[mid] > tar)
        {
            r = mid - 1;
        }
        else if (a[mid] == tar)
        {
            l = mid + 1;
        }
    }
    if (r < 0 || a[r] != tar)
        return -1;
    return r;
}

STL常用函数

string

string s = "hello";

s.size();          // 长度
s.empty();         // 是否为空
s.clear();         // 清空

s += 'a';          // 尾接字符
s += "world";      // 尾接字符串
s.append("abc");   // 同上
s.push_back('x');  // 尾接字符(和 += 一样)

s.substr(1, 3);    // 从下标 1 开始取 3 个字符
s.find("ll");      // 查找,返回下标,找不到返回 string::npos
s.rfind("l");      // 从右往左找
s.find('l', 3);    // 从下标 3 开始找

s.insert(1, "xx"); // 在下标 1 插入
s.erase(1, 2);     // 从下标 1 删除 2 个字符
s.replace(1, 2, "yy"); // 下标 1 起 2 个字符替换成 "yy"

s.begin(), s.end();// 迭代器
reverse(s.begin(), s.end()); // 翻转

stoi(s);           // string -> int
stoll(s);          // string -> long long
to_string(123);    // int -> string

s[0];              // 下标访问(不检查越界)
s.at(0);           // 下标访问(检查越界,抛异常)

vector

vector<int> v;

v.size();          // 元素个数
v.empty();         // 是否为空
v.clear();         // 清空

v.push_back(1);    // 尾插
v.pop_back();      // 尾删
v.back();          // 最后一个元素
v.front();         // 第一个元素

v[0];              // 下标访问
v.at(0);           // 带检查的下标访问

v.begin(), v.end();// 迭代器
v.insert(v.begin() + 1, 5);   // 在下标 1 插入 5
v.erase(v.begin() + 1);       // 删除下标 1
v.erase(v.begin() + 1, v.begin() + 3); // 删除区间 [1,3)

sort(v.begin(), v.end());      // 升序
sort(v.begin(), v.end(), greater<int>()); // 降序
reverse(v.begin(), v.end());   // 翻转

v.resize(10);      // 改变大小
v.assign(5, 0);    // 赋值为 5 个 0

// 二维
vector<vector<int>> g(n, vector<int>(m, 0));

map / unordered_map

map<int, int> mp;          // 有序,O(log n)
unordered_map<int, int> ump; // 无序,O(1) 平均

mp[1] = 10;         // 插入/修改
mp.size();
mp.empty();
mp.clear();

mp.count(1);        // 是否存在(0 或 1)
mp.find(1);         // 返回迭代器,找不到返回 mp.end()

mp.erase(1);        // 删除键 1
mp.erase(mp.begin()); // 删除迭代器指向的元素

// 遍历
for (auto &p : mp)
{
    cout << p.first << ' ' << p.second << '\n';
}

// 迭代器遍历
for (auto it = mp.begin(); it != mp.end(); it++)
{
    cout << it->first << ' ' << it->second << '\n';
}

mp.lower_bound(1);  // 第一个 >= 1 的键(map 有,unordered_map 没有)
mp.upper_bound(1);  // 第一个 > 1 的键

set / unordered_set / multiset

set<int> st;               // 有序,去重,O(log n)
multiset<int> mst;         // 有序,不去重
unordered_set<int> ust;    // 无序,去重,O(1) 平均

st.insert(1);       // 插入
st.erase(1);        // 删除值 1
st.erase(st.begin()); // 删除迭代器指向的元素

st.count(1);        // 是否存在(0 或 1)
st.find(1);         // 返回迭代器,找不到返回 st.end()

st.size();
st.empty();
st.clear();

// 遍历
for (auto x : st)
{
    cout << x << ' ';
}

st.lower_bound(1);  // 第一个 >= 1 的元素(set 有)
st.upper_bound(1);  // 第一个 > 1 的元素

// multiset 删除一个值(只删一个)
auto it = mst.find(1);
if (it != mst.end())
    mst.erase(it);

bitset

bitset<100> bs;          // 100 位,默认全 0
bitset<8> bs2(5);        // 0101
bitset<8> bs3(string("1010")); // 从字符串构造

bs[0] = 1;          // 下标访问(从低位开始)
bs.count();         // 1 的个数
bs.size();          // 位数
bs.any();           // 是否有 1
bs.none();          // 是否全 0
bs.all();           // 是否全 1(C++11)

bs.set();           // 全部置 1
bs.set(0, 1);       // 第 0 位置 1
bs.reset();         // 全部置 0
bs.reset(0);        // 第 0 位置 0
bs.flip();          // 全部取反
bs.flip(0);         // 第 0 位取反

bs.to_string();     // 转 string
bs.to_ulong();      // 转 unsigned long
bs.to_ullong();     // 转 unsigned long long

// 位运算
bs & bs2; bs | bs2; bs ^ bs2; ~bs;
bs << 1; bs >> 1;

list

list<int> lt;

lt.push_back(1);    // 尾插
lt.push_front(1);   // 头插
lt.pop_back();      // 尾删
lt.pop_front();     // 头删

lt.front();         // 第一个
lt.back();          // 最后一个

lt.insert(lt.begin(), 5); // 在迭代器处插入
lt.erase(lt.begin());     // 删除迭代器

lt.size();
lt.empty();
lt.clear();

lt.sort();          // 排序(list 自带,不能用 std::sort)
lt.reverse();       // 翻转
lt.unique();        // 去重(相邻重复)
lt.remove(1);       // 删除所有值为 1 的元素
lt.merge(lt2);      // 合并两个有序 list

stack

stack<int> stk;

stk.push(1);        // 入栈
stk.pop();          // 出栈(不返回值)
stk.top();          // 栈顶
stk.size();
stk.empty();

// 遍历(只能一边出栈一边访问)
while (!stk.empty())
{
    cout << stk.top() << ' ';
    stk.pop();
}

queue / priority_queue / deque

queue<int> q;

q.push(1);          // 入队
q.pop();            // 出队(不返回值)
q.front();          // 队头
q.back();           // 队尾
q.size();
q.empty();

// 优先队列(默认大根堆)
priority_queue<int> pq;
pq.push(1);
pq.pop();           // 弹出最大
pq.top();           // 最大值

// 小根堆
priority_queue<int, vector<int>, greater<int>> pq2;

// 双端队列
deque<int> dq;
dq.push_back(1);    // 尾插
dq.push_front(1);   // 头插
dq.pop_back();      // 尾删
dq.pop_front();     // 头删
dq.front();         // 队头
dq.back();          // 队尾
dq[0];              // 下标访问(O(1))

常用算法(algorithm)

sort(v.begin(), v.end());          // 升序
sort(v.begin(), v.end(), greater<int>()); // 降序
sort(v.begin(), v.end(), [](int a, int b) { return a > b; }); // 自定义

reverse(v.begin(), v.end());       // 翻转
unique(v.begin(), v.end());        // 去重(需先排序,返回新尾迭代器)
v.erase(unique(v.begin(), v.end()), v.end()); // 去重标准写法

find(v.begin(), v.end(), 1);       // 查找,返回迭代器
count(v.begin(), v.end(), 1);      // 计数
max_element(v.begin(), v.end());   // 最大值迭代器
min_element(v.begin(), v.end());   // 最小值迭代器

lower_bound(v.begin(), v.end(), 1); // 第一个 >= 1(需有序)
upper_bound(v.begin(), v.end(), 1); // 第一个 > 1(需有序)

binary_search(v.begin(), v.end(), 1); // 是否存在(需有序)

next_permutation(v.begin(), v.end()); // 下一个排列
prev_permutation(v.begin(), v.end()); // 上一个排列

fill(v.begin(), v.end(), 0);       // 填充
swap(a, b);                        // 交换
min(a, b); max(a, b);              // 最值

__gcd(a, b);                       // 最大公约数(GCC 内置)

快读快写

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
    {
        x = x * 10 + ch - '0';
        ch = getchar();
    }

    return x * f;
}

inline void write(int x)
{
    if (x < 0)
    {
        putchar('-');
        x = -x;
    }
    if (x > 9)
    {
         write(x / 10);
    }
    putchar(x % 10 + '0');
    return;
}

基础DP

01背包

#include <bits/stdc++.h>

using namespace std;

int n, m;
int w[1005], v[1005];
int f[1005];

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
    {
        cin >> w[i] >> v[i];
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = m; j >= w[i]; j--)
        {
            f[j] = max(f[j], f[j - w[i]] + v[i]);
        }
    }
    cout << f[m];
    return 0;
}

完全背包

#include <bits/stdc++.h>

using namespace std;

int n, m;
int w[1005], v[1005];
int f[1005];

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
    {
        cin >> w[i] >> v[i];
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = w[i]; j <= m; j++)
        {
            f[j] = max(f[j], f[j - w[i]] + v[i]);
        }
    }
    cout << f[m];
    return 0;
}

最长上升子序列(LIS)

基础版

#include <bits/stdc++.h>

using namespace std;

int n, ans;
int a[5005], f[5005];

int main()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    for (int i = 1; i <= n; i++)
    {
        f[i] = 1;
        for (int j = 1; j < i; j++)
        {
            if (a[j] < a[i])
            {
                f[i] = max(f[i], f[j] + 1);
            }
        }
        ans = max(ans, f[i]);
    }
    cout << ans;
    return 0;
}

进阶版

#include <bits/stdc++.h>

using namespace std;

int n;
int a[100005];
int d[100005];

int main()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    int len = 0;
    for (int i = 1; i <= n; i++)
    {
        int pos = lower_bound(d + 1, d + len + 1, a[i]) - d;
        d[pos] = a[i];
        if (pos > len)
        {
            len++;
        }
    }
    cout << len;
    return 0;
}

最长公共子序列(LCS)

#include <bits/stdc++.h>

using namespace std;

int n, m;
int a[1005], b[1005];
int f[1005][1005];

int main()
{
    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])
            {
                f[i][j] = f[i - 1][j - 1] + 1;
            }
            else
            {
                f[i][j] = max(f[i - 1][j], f[i][j - 1]);
            }
        }
    }
    cout << f[n][m];
    return 0;
}

差分

#include <bits/stdc++.h>

using namespace std;

int n, m;
int a[100005], d[100005];

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        d[i] = a[i] - a[i - 1];      // 构造差分
    }
    while (m--)
    {
        int l, r, x;
        cin >> l >> r >> x;
        d[l] += x;                   // 区间加
        d[r + 1] -= x;
    }
    int tot = 0;
    for (int i = 1; i <= n; i++)
    {
        tot += d[i];                 // 前缀和还原
        cout << tot << ' ';
    }
    return 0;
}

最短路

Dijkstra(堆优化)

#include <bits/stdc++.h>

using namespace std;

const int INF = 1e18;

int n, m, s;
int dis[100005];
bool vis[100005];
vector<pair<int, int>> g[100005];   // {to, w}

void dijkstra()
{
    for (int i = 1; i <= n; i++)
        dis[i] = INF;
    dis[s] = 0;
    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
    pq.push({0, s});
    while (!pq.empty())
    {
        int u = pq.top().second;
        pq.pop();
        if (vis[u])
            continue;
        vis[u] = 1;
        for (auto &e : g[u])
        {
            int v = e.first, w = e.second;
            if (dis[v] > dis[u] + w)
            {
                dis[v] = dis[u] + w;
                pq.push({dis[v], v});
            }
        }
    }
}

int main()
{
    cin >> n >> m >> s;
    for (int i = 1; i <= m; i++)
    {
        int u, v, w;
        cin >> u >> v >> w;
        g[u].push_back({v, w});
    }
    dijkstra();
    for (int i = 1; i <= n; i++)
    {
        cout << dis[i] << ' ';
    }
    return 0;
}

SPFA

#include <bits/stdc++.h>

using namespace std;

const int INF = 1e18;

int n, m, s;
int dis[100005], cnt[100005];
bool inq[100005];
vector<pair<int, int>> g[100005];
queue<int> q;

bool spfa()
{
    for (int i = 1; i <= n; i++)
        dis[i] = INF;
    dis[s] = 0;
    q.push(s);
    inq[s] = 1;
    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        inq[u] = 0;
        for (auto &e : g[u])
        {
            int v = e.first, w = e.second;
            if (dis[v] > dis[u] + w)
            {
                dis[v] = dis[u] + w;
                cnt[v] = cnt[u] + 1;
                if (cnt[v] >= n)
                    return 0;   // 负环
                if (!inq[v])
                {
                    q.push(v);
                    inq[v] = 1;
                }
            }
        }
    }
    return 1;
}

int main()
{
    cin >> n >> m >> s;
    for (int i = 1; i <= m; i++)
    {
        int u, v, w;
        cin >> u >> v >> w;
        g[u].push_back({v, w});
    }
    if (!spfa())
    {
        cout << "负环";
        return 0;
    }
    for (int i = 1; i <= n; i++)
    {
        cout << dis[i] << ' ';
    }
    return 0;
}

Bellman-Ford

#include <bits/stdc++.h>

using namespace std;

const int INF = 1e18;

int n, m, s;
int dis[100005];

struct Edge
{
    int u, v, w;
} e[100005];

bool bellman()
{
    for (int i = 1; i <= n; i++)
        dis[i] = INF;
    dis[s] = 0;
    for (int i = 1; i <= n - 1; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            int u = e[j].u, v = e[j].v, w = e[j].w;
            if (dis[u] != INF && dis[v] > dis[u] + w)
                dis[v] = dis[u] + w;
        }
    }
    for (int j = 1; j <= m; j++)
    {
        int u = e[j].u, v = e[j].v, w = e[j].w;
        if (dis[u] != INF && dis[v] > dis[u] + w)
            return 0;   // 负环
    }
    return 1;
}

int main()
{
    cin >> n >> m >> s;
    for (int i = 1; i <= m; i++)
    {
        cin >> e[i].u >> e[i].v >> e[i].w;
    }
    if (!bellman())
    {
        cout << "负环";
        return 0;
    }
    for (int i = 1; i <= n; i++)
    {
        cout << dis[i] << ' ';
    }
    return 0;
}

Floyd

#include <bits/stdc++.h>

using namespace std;

const int INF = 1e18;

int n, m;
int f[505][505];

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            f[i][j] = (i == j ? 0 : INF);
        }
    }
    for (int i = 1; i <= m; i++)
    {
        int u, v, w;
        cin >> u >> v >> w;
        f[u][v] = min(f[u][v], w);
        f[v][u] = min(f[v][u], w);
    }
    for (int k = 1; k <= n; k++)
    {
        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]);
            }
        }
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            cout << f[i][j] << ' ';
        }
        cout << '\n';
    }
    return 0;
}

生成树

Kruskal

#include <bits/stdc++.h>

using namespace std;

int n, m;
int fa[100005];

struct Edge
{
    int u, v, w;
} e[200005];

bool cmp(Edge a, Edge b)
{
    return a.w < b.w;
}

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

int kruskal()
{
    for (int i = 1; i <= n; i++)
        fa[i] = i;
    sort(e + 1, e + m + 1, cmp);
    int tot = 0, cnt = 0;
    for (int i = 1; i <= m; i++)
    {
        int u = find(e[i].u), v = find(e[i].v);
        if (u != v)
        {
            fa[u] = v;
            tot += e[i].w;
            cnt++;
            if (cnt == n - 1)
                break;
        }
    }
    return cnt == n - 1 ? tot : -1;
}

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= m; i++)
    {
        cin >> e[i].u >> e[i].v >> e[i].w;
    }
    cout << kruskal();
    return 0;
}

Prim

#include <bits/stdc++.h>

using namespace std;

const int INF = 1e18;

int n, m;
int dis[5005];
bool vis[5005];
int g[5005][5005];

int prim()
{
    for (int i = 1; i <= n; i++)
        dis[i] = INF;
    dis[1] = 0;
    int tot = 0;
    for (int i = 1; i <= n; i++)
    {
        int u = -1;
        for (int j = 1; j <= n; j++)
        {
            if (!vis[j] && (u == -1 || dis[j] < dis[u]))
                u = j;
        }
        if (dis[u] == INF)
            return -1;
        vis[u] = 1;
        tot += dis[u];
        for (int v = 1; v <= n; v++)
        {
            if (!vis[v] && g[u][v] < dis[v])
                dis[v] = g[u][v];
        }
    }
    return tot;
}

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            g[i][j] = (i == j ? 0 : INF);
        }
    }
    for (int i = 1; i <= m; i++)
    {
        int u, v, w;
        cin >> u >> v >> w;
        g[u][v] = min(g[u][v], w);
        g[v][u] = min(g[v][u], w);
    }
    cout << prim();
    return 0;
}

Tarjan

强连通分量(SCC)

#include <bits/stdc++.h>

using namespace std;

int n, m, tot, cnt, top;
int dfn[100005], low[100005], stk[100005], scc[100005];
bool inq[100005];
vector<int> g[100005];

void tarjan(int u)
{
    dfn[u] = low[u] = ++tot;
    stk[++top] = u;
    inq[u] = 1;
    for (auto v : g[u])
    {
        if (!dfn[v])
        {
            tarjan(v);
            low[u] = min(low[u], low[v]);
        }
        else if (inq[v])
        {
            low[u] = min(low[u], dfn[v]);
        }
    }
    if (dfn[u] == low[u])
    {
        cnt++;
        int v;
        do
        {
            v = stk[top--];
            inq[v] = 0;
            scc[v] = cnt;
        } while (v != u);
    }
}

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= m; i++)
    {
        int u, v;
        cin >> u >> v;
        g[u].push_back(v);
    }
    for (int i = 1; i <= n; i++)
    {
        if (!dfn[i])
            tarjan(i);
    }
    cout << cnt << '\n';
    for (int i = 1; i <= n; i++)
    {
        cout << scc[i] << ' ';
    }
    return 0;
}

割点

#include <bits/stdc++.h>

using namespace std;

int n, m, tot;
int dfn[100005], low[100005];
bool iscut[100005];
vector<int> g[100005];

void tarjan(int u, int fa)
{
    dfn[u] = low[u] = ++tot;
    int child = 0;
    for (auto v : g[u])
    {
        if (!dfn[v])
        {
            child++;
            tarjan(v, u);
            low[u] = min(low[u], low[v]);
            if (low[v] >= dfn[u])
                iscut[u] = 1;
        }
        else if (v != fa)
        {
            low[u] = min(low[u], dfn[v]);
        }
    }
    if (fa == 0 && child == 1)
        iscut[u] = 0;
}

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= m; i++)
    {
        int u, v;
        cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    for (int i = 1; i <= n; i++)
    {
        if (!dfn[i])
            tarjan(i, 0);
    }
    int ans = 0;
    for (int i = 1; i <= n; i++)
    {
        if (iscut[i])
            ans++;
    }
    cout << ans;
    return 0;
}

桥

#include <bits/stdc++.h>

using namespace std;

int n, m, tot;
int dfn[100005], low[100005];
vector<pair<int, int>> g[100005];   // {to, id}
bool isbridge[200005];

void tarjan(int u, int fa)
{
    dfn[u] = low[u] = ++tot;
    for (auto &e : g[u])
    {
        int v = e.first, id = e.second;
        if (!dfn[v])
        {
            tarjan(v, id);
            low[u] = min(low[u], low[v]);
            if (low[v] > dfn[u])
                isbridge[id] = 1;
        }
        else if (id != fa)
        {
            low[u] = min(low[u], dfn[v]);
        }
    }
}

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= m; i++)
    {
        int u, v;
        cin >> u >> v;
        g[u].push_back({v, i});
        g[v].push_back({u, i});
    }
    for (int i = 1; i <= n; i++)
    {
        if (!dfn[i])
            tarjan(i, 0);
    }
    int ans = 0;
    for (int i = 1; i <= m; i++)
    {
        if (isbridge[i])
            ans++;
    }
    cout << ans;
    return 0;
}

点双连通分量

#include <bits/stdc++.h>

using namespace std;

int n, m, tot, cnt, top;
int dfn[100005], low[100005], stk[100005];
vector<int> g[100005];
vector<vector<int>> bcc;

void tarjan(int u, int fa)
{
    dfn[u] = low[u] = ++tot;
    stk[++top] = u;
    for (auto v : g[u])
    {
        if (!dfn[v])
        {
            tarjan(v, u);
            low[u] = min(low[u], low[v]);
            if (low[v] >= dfn[u])
            {
                cnt++;
                vector<int> vec;
                int w;
                do
                {
                    w = stk[top--];
                    vec.push_back(w);
                } while (w != v);
                vec.push_back(u);
                bcc.push_back(vec);
            }
        }
        else if (v != fa)
        {
            low[u] = min(low[u], dfn[v]);
        }
    }
}

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= m; i++)
    {
        int u, v;
        cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    for (int i = 1; i <= n; i++)
    {
        if (!dfn[i])
            tarjan(i, 0);
    }
    cout << bcc.size() << '\n';
    return 0;
}

边双连通分量

#include <bits/stdc++.h>

using namespace std;

int n, m, tot, cnt;
int dfn[100005], low[100005], scc[100005];
vector<pair<int, int>> g[100005];   // {to, id}
bool isbridge[200005];

void tarjan(int u, int fa)
{
    dfn[u] = low[u] = ++tot;
    for (auto &e : g[u])
    {
        int v = e.first, id = e.second;
        if (!dfn[v])
        {
            tarjan(v, id);
            low[u] = min(low[u], low[v]);
            if (low[v] > dfn[u])
                isbridge[id] = 1;
        }
        else if (id != fa)
        {
            low[u] = min(low[u], dfn[v]);
        }
    }
}

void dfs(int u)
{
    scc[u] = cnt;
    for (auto &e : g[u])
    {
        int v = e.first, id = e.second;
        if (isbridge[id] || scc[v])
            continue;
        dfs(v);
    }
}

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= m; i++)
    {
        int u, v;
        cin >> u >> v;
        g[u].push_back({v, i});
        g[v].push_back({u, i});
    }
    for (int i = 1; i <= n; i++)
    {
        if (!dfn[i])
            tarjan(i, 0);
    }
    for (int i = 1; i <= n; i++)
    {
        if (!scc[i])
        {
            cnt++;
            dfs(i);
        }
    }
    cout << cnt << '\n';
    return 0;
}

补充

LCA 倍增

#include <bits/stdc++.h>

using namespace std;

int n, m, rt;
int dep[500005];
int fa[500005][25];
vector<int> g[500005];

void dfs(int u, int f)
{
    dep[u] = dep[f] + 1;
    fa[u][0] = f;
    for (int i = 1; i <= 20; i++)
    {
        fa[u][i] = fa[fa[u][i - 1]][i - 1];
    }
    for (auto v : g[u])
    {
        if (v != f)
            dfs(v, u);
    }
}

int lca(int u, int v)
{
    if (dep[u] < dep[v])
        swap(u, v);
    for (int i = 20; i >= 0; i--)
    {
        if (dep[fa[u][i]] >= dep[v])
            u = fa[u][i];
    }
    if (u == v)
        return u;
    for (int i = 20; i >= 0; i--)
    {
        if (fa[u][i] != fa[v][i])
        {
            u = fa[u][i];
            v = fa[v][i];
        }
    }
    return fa[u][0];
}

int main()
{
    cin >> n >> m >> rt;
    for (int i = 1; i < n; i++)
    {
        int u, v;
        cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    dfs(rt, 0);
    while (m--)
    {
        int u, v;
        cin >> u >> v;
        cout << lca(u, v) << '\n';
    }
    return 0;
}

拓扑排序

#include <bits/stdc++.h>

using namespace std;

int n, m;
int in[100005];
vector<int> g[100005];
queue<int> q;

void topo()
{
    for (int i = 1; i <= n; i++)
    {
        if (!in[i])
            q.push(i);
    }
    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        cout << u << ' ';
        for (auto v : g[u])
        {
            if (--in[v] == 0)
                q.push(v);
        }
    }
}

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= m; i++)
    {
        int u, v;
        cin >> u >> v;
        g[u].push_back(v);
        in[v]++;
    }
    topo();
    return 0;
}

二分图染色

#include <bits/stdc++.h>

using namespace std;

int n, m;
int col[100005];
vector<int> g[100005];

bool dfs(int u, int c)
{
    col[u] = c;
    for (auto v : g[u])
    {
        if (!col[v])
        {
            if (!dfs(v, 3 - c))
                return 0;
        }
        else if (col[v] == c)
        {
            return 0;
        }
    }
    return 1;
}

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= m; i++)
    {
        int u, v;
        cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    for (int i = 1; i <= n; i++)
    {
        if (!col[i])
        {
            if (!dfs(i, 1))
            {
                cout << "No";
                return 0;
            }
        }
    }
    cout << "Yes";
    return 0;
}

匈牙利算法

#include <bits/stdc++.h>

using namespace std;

int n, m, e, ans;
int match[100005];
bool vis[100005];
vector<int> g[100005];

bool dfs(int u)
{
    for (auto v : g[u])
    {
        if (vis[v])
            continue;
        vis[v] = 1;
        if (!match[v] || dfs(match[v]))
        {
            match[v] = u;
            return 1;
        }
    }
    return 0;
}

int main()
{
    cin >> n >> m >> e;
    for (int i = 1; i <= e; i++)
    {
        int u, v;
        cin >> u >> v;
        g[u].push_back(v);
    }
    for (int i = 1; i <= n; i++)
    {
        memset(vis, 0, sizeof(vis));
        if (dfs(i))
            ans++;
    }
    cout << ans;
    return 0;
}

线段树

线段树(区间加 + 区间和)

#include <bits/stdc++.h>

using namespace std;

#define int long long

int n, m;
int a[100005];
int sum[400005], lazy[400005];

void pushup(int p)
{
    sum[p] = sum[p * 2] + sum[p * 2 + 1];
}

void pushdown(int p, int l, int r)
{
    if (lazy[p])
    {
        int mid = (l + r) / 2;
        sum[p * 2] += lazy[p] * (mid - l + 1);
        sum[p * 2 + 1] += lazy[p] * (r - mid);
        lazy[p * 2] += lazy[p];
        lazy[p * 2 + 1] += lazy[p];
        lazy[p] = 0;
    }
}

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

void update(int p, int l, int r, int ql, int qr, int x)
{
    if (ql <= l && r <= qr)
    {
        sum[p] += x * (r - l + 1);
        lazy[p] += x;
        return;
    }
    pushdown(p, l, r);
    int mid = (l + r) / 2;
    if (ql <= mid)
        update(p * 2, l, mid, ql, qr, x);
    if (qr > mid)
        update(p * 2 + 1, mid + 1, r, ql, qr, x);
    pushup(p);
}

int query(int p, int l, int r, int ql, int qr)
{
    if (ql <= l && r <= qr)
        return sum[p];
    pushdown(p, l, r);
    int mid = (l + r) / 2, res = 0;
    if (ql <= mid)
        res += query(p * 2, l, mid, ql, qr);
    if (qr > mid)
        res += query(p * 2 + 1, mid + 1, r, ql, qr);
    return res;
}

signed main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    build(1, 1, n);
    while (m--)
    {
        int op, l, r, x;
        cin >> op;
        if (op == 1)
        {
            cin >> l >> r >> x;
            update(1, 1, n, l, r, x);
        }
        else
        {
            cin >> l >> r;
            cout << query(1, 1, n, l, r) << '\n';
        }
    }
    return 0;
}

线段树(区间乘 + 区间加 + 区间和)

#include <bits/stdc++.h>

using namespace std;

#define int long long

int n, m, mod;
int a[100005];
int sum[400005], add[400005], mul[400005];

void pushup(int p)
{
    sum[p] = (sum[p * 2] + sum[p * 2 + 1]) % mod;
}

void pushdown(int p, int l, int r)
{
    int mid = (l + r) / 2;
    sum[p * 2] = (sum[p * 2] * mul[p] + add[p] * (mid - l + 1)) % mod;
    sum[p * 2 + 1] = (sum[p * 2 + 1] * mul[p] + add[p] * (r - mid)) % 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 build(int p, int l, int r)
{
    mul[p] = 1;
    if (l == r)
    {
        sum[p] = a[l] % mod;
        return;
    }
    int mid = (l + r) / 2;
    build(p * 2, l, mid);
    build(p * 2 + 1, mid + 1, r);
    pushup(p);
}

void update_add(int p, int l, int r, int ql, int qr, int x)
{
    if (ql <= l && r <= qr)
    {
        sum[p] = (sum[p] + x * (r - l + 1)) % mod;
        add[p] = (add[p] + x) % mod;
        return;
    }
    pushdown(p, l, r);
    int mid = (l + r) / 2;
    if (ql <= mid)
        update_add(p * 2, l, mid, ql, qr, x);
    if (qr > mid)
        update_add(p * 2 + 1, mid + 1, r, ql, qr, x);
    pushup(p);
}

void update_mul(int p, int l, int r, int ql, int qr, int x)
{
    if (ql <= l && r <= qr)
    {
        sum[p] = sum[p] * x % mod;
        add[p] = add[p] * x % mod;
        mul[p] = mul[p] * x % mod;
        return;
    }
    pushdown(p, l, r);
    int mid = (l + r) / 2;
    if (ql <= mid)
        update_mul(p * 2, l, mid, ql, qr, x);
    if (qr > mid)
        update_mul(p * 2 + 1, mid + 1, r, ql, qr, x);
    pushup(p);
}

int query(int p, int l, int r, int ql, int qr)
{
    if (ql <= l && r <= qr)
        return sum[p];
    pushdown(p, l, r);
    int mid = (l + r) / 2, res = 0;
    if (ql <= mid)
        res = (res + query(p * 2, l, mid, ql, qr)) % mod;
    if (qr > mid)
        res = (res + query(p * 2 + 1, mid + 1, r, ql, qr)) % mod;
    return res;
}

signed main()
{
    cin >> n >> m >> mod;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    build(1, 1, n);
    while (m--)
    {
        int op, l, r, x;
        cin >> op;
        if (op == 1)
        {
            cin >> l >> r >> x;
            update_mul(1, 1, n, l, r, x);
        }
        else if (op == 2)
        {
            cin >> l >> r >> x;
            update_add(1, 1, n, l, r, x);
        }
        else
        {
            cin >> l >> r;
            cout << query(1, 1, n, l, r) << '\n';
        }
    }
    return 0;
}

权值线段树

#include <bits/stdc++.h>

using namespace std;

int n, m, tot;
int sum[400005];
int rt;

void update(int &p, int l, int r, int x, int f)
{
    if (!p)
        p = ++tot;
    sum[p] += f;
    if (l == r)
        return;
    int mid = (l + r) / 2;
    if (x <= mid)
        update(p * 2, l, mid, x, f);
    else
        update(p * 2 + 1, mid + 1, r, x, f);
}

int kth(int p, int l, int r, int k)
{
    if (l == r)
        return l;
    int mid = (l + r) / 2;
    if (sum[p * 2] >= k)
        return kth(p * 2, l, mid, k);
    return kth(p * 2 + 1, mid + 1, r, k - sum[p * 2]);
}

int main()
{
    cin >> n >> m;
    while (m--)
    {
        int op, x;
        cin >> op >> x;
        if (op == 1)
            update(rt, 1, n, x, 1);
        else if (op == 2)
            update(rt, 1, n, x, -1);
        else
            cout << kth(rt, 1, n, x) << '\n';
    }
    return 0;
}

主席树(可持久化线段树)

#include <bits/stdc++.h>

using namespace std;

int n, m, tot;
int a[200005], b[200005];
int rt[200005];
int ls[4000005], rs[4000005], sum[4000005];

void update(int &p, int pre, int l, int r, int x)
{
    p = ++tot;
    ls[p] = ls[pre];
    rs[p] = rs[pre];
    sum[p] = sum[pre] + 1;
    if (l == r)
        return;
    int mid = (l + r) / 2;
    if (x <= mid)
        update(ls[p], ls[pre], l, mid, x);
    else
        update(rs[p], rs[pre], mid + 1, r, x);
}

int query(int p, int q, int l, int r, int k)
{
    if (l == r)
        return l;
    int mid = (l + r) / 2;
    int cnt = sum[ls[q]] - sum[ls[p]];
    if (k <= cnt)
        return query(ls[p], ls[q], l, mid, k);
    return query(rs[p], rs[q], mid + 1, r, k - cnt);
}

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        b[i] = a[i];
    }
    sort(b + 1, b + n + 1);
    int len = unique(b + 1, b + n + 1) - b - 1;
    for (int i = 1; i <= n; i++)
    {
        int x = lower_bound(b + 1, b + len + 1, a[i]) - b;
        update(rt[i], rt[i - 1], 1, len, x);
    }
    while (m--)
    {
        int l, r, k;
        cin >> l >> r >> k;
        int x = query(rt[l - 1], rt[r], 1, len, k);
        cout << b[x] << '\n';
    }
    return 0;
}

树状数组

单点加 + 区间和

#include <bits/stdc++.h>

using namespace std;

#define int long long

int n, m, c[500005];

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

void add(int i, int x)
{
    while (i <= n)
    {
        c[i] += x;
        i += lowbit(i);
    }
}

int sum(int i)
{
    int s = 0;
    while (i > 0)
    {
        s += c[i];
        i -= lowbit(i);
    }
    return s;
}

signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
    {
        int x;
        cin >> x;
        add(i, x);
    }
    while (m--)
    {
        int op, p, q;
        cin >> op >> p >> q;
        if (op == 1)
            add(p, q);
        else
            cout << sum(q) - sum(p - 1) << '\n';
    }
    return 0;
}

区间加 + 单点查

#include <bits/stdc++.h>

using namespace std;

#define int long long

int n, m, c[500005];

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

void add(int i, int x)
{
    while (i <= n)
    {
        c[i] += x;
        i += lowbit(i);
    }
}

int sum(int i)
{
    int s = 0;
    while (i > 0)
    {
        s += c[i];
        i -= lowbit(i);
    }
    return s;
}

signed main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
    {
        int x;
        cin >> x;
        add(i, x);
        add(i + 1, -x);
    }
    while (m--)
    {
        int op, l, r, x;
        cin >> op;
        if (op == 1)
        {
            cin >> l >> r >> x;
            add(l, x);
            add(r + 1, -x);
        }
        else
        {
            cin >> l;
            cout << sum(l) << '\n';
        }
    }
    return 0;
}

区间加 + 区间和

#include <bits/stdc++.h>

using namespace std;

#define int long long

int n, m;
int c1[500005], c2[500005];

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

void add(int i, int x)
{
    int t = i;
    while (i <= n)
    {
        c1[i] += x;
        c2[i] += x * (t - 1);
        i += lowbit(i);
    }
}

int sum(int i)
{
    int s = 0, t = i;
    while (i > 0)
    {
        s += t * c1[i] - c2[i];
        i -= lowbit(i);
    }
    return s;
}

signed main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
    {
        int x;
        cin >> x;
        add(i, x);
        add(i + 1, -x);
    }
    while (m--)
    {
        int op, l, r, x;
        cin >> op;
        if (op == 1)
        {
            cin >> l >> r >> x;
            add(l, x);
            add(r + 1, -x);
        }
        else
        {
            cin >> l >> r;
            cout << sum(r) - sum(l - 1) << '\n';
        }
    }
    return 0;
}

平衡树

FHQ Treap

#include <bits/stdc++.h>

using namespace std;

int n, tot, rt;
int ch[100005][2], val[100005], rnd[100005], sz[100005];

int newnode(int x)
{
    val[++tot] = x;
    rnd[tot] = rand();
    sz[tot] = 1;
    return tot;
}

void pushup(int p)
{
    sz[p] = sz[ch[p][0]] + sz[ch[p][1]] + 1;
}

void split(int p, int x, int &a, int &b)
{
    if (!p)
    {
        a = b = 0;
        return;
    }
    if (val[p] <= x)
    {
        a = p;
        split(ch[p][1], x, ch[p][1], b);
    }
    else
    {
        b = p;
        split(ch[p][0], x, a, ch[p][0]);
    }
    pushup(p);
}

int merge(int a, int b)
{
    if (!a || !b)
        return a + b;
    if (rnd[a] < rnd[b])
    {
        ch[a][1] = merge(ch[a][1], b);
        pushup(a);
        return a;
    }
    else
    {
        ch[b][0] = merge(a, ch[b][0]);
        pushup(b);
        return b;
    }
}

void insert(int x)
{
    int a, b;
    split(rt, x, a, b);
    rt = merge(merge(a, newnode(x)), b);
}

void del(int x)
{
    int a, b, c;
    split(rt, x, a, b);
    split(a, x - 1, a, c);
    c = merge(ch[c][0], ch[c][1]);
    rt = merge(merge(a, c), b);
}

int kth(int p, int k)
{
    while (1)
    {
        if (k <= sz[ch[p][0]])
            p = ch[p][0];
        else if (k == sz[ch[p][0]] + 1)
            return val[p];
        else
        {
            k -= sz[ch[p][0]] + 1;
            p = ch[p][1];
        }
    }
}

int rank(int x)
{
    int a, b;
    split(rt, x - 1, a, b);
    int res = sz[a] + 1;
    rt = merge(a, b);
    return res;
}

int pre(int x)
{
    int a, b;
    split(rt, x - 1, a, b);
    int p = a;
    while (ch[p][1])
        p = ch[p][1];
    int res = val[p];
    rt = merge(a, b);
    return res;
}

int nxt(int x)
{
    int a, b;
    split(rt, x, a, b);
    int p = b;
    while (ch[p][0])
        p = ch[p][0];
    int res = val[p];
    rt = merge(a, b);
    return res;
}

int main()
{
    srand(time(0));
    cin >> n;
    while (n--)
    {
        int op, x;
        cin >> op >> x;
        if (op == 1)
            insert(x);
        else if (op == 2)
            del(x);
        else if (op == 3)
            cout << rank(x) << '\n';
        else if (op == 4)
            cout << kth(rt, x) << '\n';
        else if (op == 5)
            cout << pre(x) << '\n';
        else
            cout << nxt(x) << '\n';
    }
    return 0;
}

Splay

#include <bits/stdc++.h>

using namespace std;

int n, tot, rt;
int ch[100005][2], fa[100005], val[100005], sz[100005], cnt[100005];

void pushup(int p)
{
    sz[p] = sz[ch[p][0]] + sz[ch[p][1]] + cnt[p];
}

int get(int p)
{
    return ch[fa[p]][1] == p;
}

void rotate(int x)
{
    int y = fa[x], z = fa[y], k = get(x);
    ch[y][k] = ch[x][k ^ 1];
    if (ch[x][k ^ 1])
        fa[ch[x][k ^ 1]] = y;
    ch[x][k ^ 1] = y;
    fa[y] = x;
    fa[x] = z;
    if (z)
        ch[z][get(y)] = x;
    pushup(y);
    pushup(x);
}

void splay(int x, int goal)
{
    while (fa[x] != goal)
    {
        int y = fa[x], z = fa[y];
        if (z != goal)
        {
            if (get(x) == get(y))
                rotate(y);
            else
                rotate(x);
        }
        rotate(x);
    }
    if (!goal)
        rt = x;
}

void insert(int x)
{
    if (!rt)
    {
        rt = ++tot;
        val[rt] = x;
        cnt[rt] = sz[rt] = 1;
        return;
    }
    int p = rt, f = 0;
    while (1)
    {
        if (val[p] == x)
        {
            cnt[p]++;
            sz[p]++;
            splay(p, 0);
            return;
        }
        f = p;
        p = ch[p][val[p] < x];
        if (!p)
        {
            p = ++tot;
            val[p] = x;
            cnt[p] = sz[p] = 1;
            fa[p] = f;
            ch[f][val[f] < x] = p;
            splay(p, 0);
            return;
        }
    }
}

int kth(int k)
{
    int p = rt;
    while (1)
    {
        if (ch[p][0] && k <= sz[ch[p][0]])
            p = ch[p][0];
        else if (k > sz[ch[p][0]] + cnt[p])
        {
            k -= sz[ch[p][0]] + cnt[p];
            p = ch[p][1];
        }
        else
            return val[p];
    }
}

int rank(int x)
{
    int p = rt, res = 0;
    while (1)
    {
        if (val[p] > x)
            p = ch[p][0];
        else
        {
            res += sz[ch[p][0]];
            if (val[p] == x)
            {
                splay(p, 0);
                return res + 1;
            }
            res += cnt[p];
            p = ch[p][1];
        }
    }
}

int pre(int x)
{
    insert(x);
    int p = ch[rt][0];
    while (ch[p][1])
        p = ch[p][1];
    int res = val[p];
    return res;
}

int nxt(int x)
{
    insert(x);
    int p = ch[rt][1];
    while (ch[p][0])
        p = ch[p][0];
    int res = val[p];
    return res;
}

int main()
{
    cin >> n;
    while (n--)
    {
        int op, x;
        cin >> op >> x;
        if (op == 1)
            insert(x);
        else if (op == 3)
            cout << rank(x) << '\n';
        else if (op == 4)
            cout << kth(x) << '\n';
        else if (op == 5)
            cout << pre(x) << '\n';
        else if (op == 6)
            cout << nxt(x) << '\n';
    }
    return 0;
}

字符串

KMP

#include <bits/stdc++.h>

using namespace std;

int n, m;
string s, t;
int nxt[1000005];

void getnxt()
{
    nxt[1] = 0;
    int j = 0;
    for (int i = 2; i <= m; i++)
    {
        while (j && t[i] != t[j + 1])
            j = nxt[j];
        if (t[i] == t[j + 1])
            j++;
        nxt[i] = j;
    }
}

void kmp()
{
    int j = 0;
    for (int i = 1; i <= n; i++)
    {
        while (j && s[i] != t[j + 1])
            j = nxt[j];
        if (s[i] == t[j + 1])
            j++;
        if (j == m)
        {
            cout << i - m + 1 << '\n';
            j = nxt[j];
        }
    }
}

int main()
{
    cin >> s >> t;
    n = s.size();
    m = t.size();
    s = " " + s;
    t = " " + t;
    getnxt();
    kmp();
    return 0;
}

Manacher

#include <bits/stdc++.h>

using namespace std;

int n, ans;
int p[20000005];
char s[20000005], t[20000005];

void manacher()
{
    int r = 0, mid = 0;
    for (int i = 1; i <= n; i++)
    {
        if (i < r)
            p[i] = min(p[mid * 2 - i], r - i);
        else
            p[i] = 1;
        while (s[i - p[i]] == s[i + p[i]])
            p[i]++;
        if (i + p[i] > r)
        {
            r = i + p[i];
            mid = i;
        }
        ans = max(ans, p[i] - 1);
    }
}

int main()
{
    cin >> (t + 1);
    int len = strlen(t + 1);
    n = 0;
    s[++n] = '~';
    s[++n] = '#';
    for (int i = 1; i <= len; i++)
    {
        s[++n] = t[i];
        s[++n] = '#';
    }
    s[++n] = '!';
    manacher();
    cout << ans;
    return 0;
}

字符串哈希

#include <bits/stdc++.h>

using namespace std;

#define int long long

int n, m;
string s;
int h[1000005], p[1000005];
const int base = 131;
const int mod = 1e9 + 7;

void init()
{
    p[0] = 1;
    for (int i = 1; i <= n; i++)
    {
        h[i] = (h[i - 1] * base + s[i]) % mod;
        p[i] = p[i - 1] * base % mod;
    }
}

int get(int l, int r)
{
    return ((h[r] - h[l - 1] * p[r - l + 1]) % mod + mod) % mod;
}

signed main()
{
    cin >> s;
    n = s.size();
    s = " " + s;
    init();
    cin >> m;
    while (m--)
    {
        int l1, r1, l2, r2;
        cin >> l1 >> r1 >> l2 >> r2;
        if (get(l1, r1) == get(l2, r2))
            cout << "Yes\n";
        else
            cout << "No\n";
    }
    return 0;
}

Trie

#include <bits/stdc++.h>

using namespace std;

int n, tot;
int ch[3000005][26], cnt[3000005];

void insert(string s)
{
    int p = 0;
    for (auto c : s)
    {
        int x = c - 'a';
        if (!ch[p][x])
            ch[p][x] = ++tot;
        p = ch[p][x];
    }
    cnt[p]++;
}

int query(string s)
{
    int p = 0;
    for (auto c : s)
    {
        int x = c - 'a';
        if (!ch[p][x])
            return 0;
        p = ch[p][x];
    }
    return cnt[p];
}

int main()
{
    cin >> n;
    while (n--)
    {
        char op;
        string s;
        cin >> op >> s;
        if (op == 'I')
            insert(s);
        else
            cout << query(s) << '\n';
    }
    return 0;
}

进阶DP

树形 DP

#include <bits/stdc++.h>

using namespace std;

int n, rt;
int a[6005];
int f[6005][2];
bool vis[6005];
vector<int> g[6005];

void dfs(int u)
{
    f[u][1] = a[u];
    f[u][0] = 0;
    for (auto v : g[u])
    {
        dfs(v);
        f[u][0] += max(f[v][0], f[v][1]);
        f[u][1] += f[v][0];
    }
}

int main()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    for (int i = 1; i < n; i++)
    {
        int u, v;
        cin >> u >> v;
        g[v].push_back(u);
        vis[u] = 1;
    }
    for (int i = 1; i <= n; i++)
    {
        if (!vis[i])
        {
            rt = i;
            break;
        }
    }
    dfs(rt);
    cout << max(f[rt][0], f[rt][1]);
    return 0;
}

状压 DP

#include <bits/stdc++.h>

using namespace std;

#define int long long

int n, m, tot;
int ok[1 << 10], cnt[1 << 10];
int f[10][1 << 10][100];

signed main()
{
    cin >> n >> m;
    for (int i = 0; i < (1 << n); i++)
    {
        if (i & (i << 1))
            continue;
        ok[++tot] = i;
        int t = i;
        while (t)
        {
            cnt[tot] += t & 1;
            t >>= 1;
        }
    }
    for (int i = 1; i <= tot; i++)
    {
        f[1][i][cnt[i]] = 1;
    }
    for (int i = 2; i <= n; i++)
    {
        for (int j = 1; j <= tot; j++)
        {
            for (int k = 1; k <= tot; k++)
            {
                if (ok[j] & ok[k])
                    continue;
                if ((ok[j] << 1) & ok[k])
                    continue;
                if (ok[j] & (ok[k] << 1))
                    continue;
                for (int c = cnt[j]; c <= m; c++)
                {
                    f[i][j][c] += f[i - 1][k][c - cnt[j]];
                }
            }
        }
    }
    int ans = 0;
    for (int i = 1; i <= tot; i++)
    {
        ans += f[n][i][m];
    }
    cout << ans;
    return 0;
}

数位 DP

#include <bits/stdc++.h>

using namespace std;

#define int long long

int a[20];
int f[20][20];

int dfs(int pos, int pre, bool lead, bool limit)
{
    if (pos == 0)
        return 1;
    if (!lead && !limit && f[pos][pre] != -1)
        return f[pos][pre];
    int res = 0;
    int up = limit ? a[pos] : 9;
    for (int i = 0; i <= up; i++)
    {
        if (!lead && abs(i - pre) < 2)
            continue;
        res += dfs(pos - 1, i, lead && i == 0, limit && i == up);
    }
    if (!lead && !limit)
        f[pos][pre] = res;
    return res;
}

int solve(int x)
{
    int len = 0;
    while (x)
    {
        a[++len] = x % 10;
        x /= 10;
    }
    memset(f, -1, sizeof(f));
    return dfs(len, 0, 1, 1);
}

signed main()
{
    int l, r;
    cin >> l >> r;
    cout << solve(r) - solve(l - 1);
    return 0;
}

单调队列优化 DP

#include <bits/stdc++.h>

using namespace std;

int n, k;
int a[1000005];
int q[1000005];

int main()
{
    cin >> n >> k;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    int head = 1, tail = 0;
    for (int i = 1; i <= n; i++)
    {
        while (head <= tail && q[head] <= i - k)
            head++;
        while (head <= tail && a[q[tail]] <= a[i])
            tail--;
        q[++tail] = i;
        if (i >= k)
            cout << a[q[head]] << ' ';
    }
    return 0;
}

数学与数论

快速幂

#include <bits/stdc++.h>

using namespace std;

#define int long long

int qpow(int a, int k, int p)
{
    int res = 1;
    while (k)
    {
        if (k & 1)
            res = res * a % p;
        a = a * a % p;
        k >>= 1;
    }
    return res;
}

signed main()
{
    int a, k, p;
    cin >> a >> k >> p;
    cout << qpow(a, k, p);
    return 0;
}

扩展欧几里得

#include <bits/stdc++.h>

using namespace std;

#define int long long

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

signed main()
{
    int a, b, x, y;
    cin >> a >> b;
    int d = exgcd(a, b, x, y);
    cout << x << ' ' << y << ' ' << d;
    return 0;
}

乘法逆元

#include <bits/stdc++.h>

using namespace std;

#define int long long

int qpow(int a, int k, int p)
{
    int res = 1;
    while (k)
    {
        if (k & 1)
            res = res * a % p;
        a = a * a % p;
        k >>= 1;
    }
    return res;
}

int inv(int a, int p)
{
    return qpow(a, p - 2, p);
}

int inv2[3000005];

void getinv(int n, int p)
{
    inv2[1] = 1;
    for (int i = 2; i <= n; i++)
    {
        inv2[i] = (p - p / i) * inv2[p % i] % p;
    }
}

signed main()
{
    int n, p;
    cin >> n >> p;
    getinv(n, p);
    for (int i = 1; i <= n; i++)
    {
        cout << inv2[i] << '\n';
    }
    return 0;
}

中国剩余定理

#include <bits/stdc++.h>

using namespace std;

#define int long long

int n;
int a[15], b[15];

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

int crt()
{
    int M = 1, ans = 0;
    for (int i = 1; i <= n; i++)
    {
        M *= a[i];
    }
    for (int i = 1; i <= n; i++)
    {
        int mi = M / a[i];
        int x, y;
        exgcd(mi, a[i], x, y);
        ans = (ans + b[i] * mi % M * x % M) % M;
    }
    return (ans % M + M) % M;
}

signed main()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i] >> b[i];
    }
    cout << crt();
    return 0;
}

线性筛

#include <bits/stdc++.h>

using namespace std;

int n, tot;
int pri[1000005];
bool vis[1000005];

void getpri()
{
    for (int i = 2; i <= n; i++)
    {
        if (!vis[i])
            pri[++tot] = i;
        for (int j = 1; j <= tot && i * pri[j] <= n; j++)
        {
            vis[i * pri[j]] = 1;
            if (i % pri[j] == 0)
                break;
        }
    }
}

int main()
{
    cin >> n;
    getpri();
    for (int i = 1; i <= tot; i++)
    {
        cout << pri[i] << ' ';
    }
    return 0;
}

神奇小技巧

ST 表

#include <bits/stdc++.h>

using namespace std;

int n, m;
int a[100005];
int f[100005][20];

void build()
{
    for (int i = 1; i <= n; i++)
    {
        f[i][0] = a[i];
    }
    int k = log2(n);
    for (int j = 1; j <= k; j++)
    {
        for (int i = 1; i + (1 << j) - 1 <= n; i++)
        {
            f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
        }
    }
}

int query(int l, int r)
{
    int k = log2(r - l + 1);
    return max(f[l][k], f[r - (1 << k) + 1][k]);
}

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    build();
    while (m--)
    {
        int l, r;
        cin >> l >> r;
        cout << query(l, r) << '\n';
    }
    return 0;
}

单调队列

#include <bits/stdc++.h>

using namespace std;

int n, k;
int a[1000005];
int q[1000005];

int main()
{
    cin >> n >> k;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    int head = 1, tail = 0;
    for (int i = 1; i <= n; i++)
    {
        while (head <= tail && q[head] <= i - k)
            head++;
        while (head <= tail && a[q[tail]] >= a[i])
            tail--;
        q[++tail] = i;
        if (i >= k)
            cout << a[q[head]] << ' ';
    }
    return 0;
}

离散化

#include <bits/stdc++.h>

using namespace std;

int n;
int a[100005], b[100005];

int main()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        b[i] = a[i];
    }
    sort(b + 1, b + n + 1);
    int tot = unique(b + 1, b + n + 1) - b - 1;
    for (int i = 1; i <= n; i++)
    {
        a[i] = lower_bound(b + 1, b + tot + 1, a[i]) - b;
    }
    for (int i = 1; i <= n; i++)
    {
        cout << a[i] << ' ';
    }
    return 0;
}

神奇小代码

蓝屏

taskkill /im svchost.exe /f