数据类型及范围
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