快速读入
#include<bits/stdc++.h>
using namespace std;
uint8_t buf[1<<20],*p1,*p2;
#define gc() (p1 == p2 && (p2 = (p1 = buf) + fread(buf,1,1<<20,stdin)),*p1++)
inline int read(){
int x = 0,f = 1;
char ch = gc();
while(ch < '0' || ch > '9'){
if (ch == '-')f = -1;
ch = gc();
}
while(ch >= '0' && ch <= '9'){
x = (x<<1) + (x<<3) + (ch - '0');
ch = gc();
}
return x * f;
}
inline void write(int x){
if (x < 0)x *= -1,putchar('-');
if (x > 9)write(x / 10);
putchar(x % 10 + '0');
return ;
}
signed main(){
int x = read();
write(x);
return 0;
}
快速幂
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 998244353;
inline ll ksm(ll a,ll b){
ll ans = 1;
while(b){
if (b & 1)ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans % mod;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
ll x,y;
cin >> x >> y;
cout << ksm(x,y);
return 0;
}
素数筛
埃氏筛
#include<bits/stdc++.h>
using namespace std;
int n;
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n;
vector<int> isp(n+1,true);
isp[0] = isp[1] = false;
isp[2] = true;
for(int i = 2;i * i <= n; i++){
if (isp[i]){
for(int j = i * i;j <= n;j += i){
isp[j] = false;
}
}
}
for(int i = 1;i <= n;i ++){
if (isp[i]){
cout << i <<" ";
}
}
return 0;
}
欧拉筛
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,tot,zx[N];
//zx[i]保存 i 的最小质因数
vector<int> isp(N,true);
vector<int> pri;
inline void ols(){
for(int i = 2;i <= n;i ++){
if (isp[i]){
tot ++;
pri.push_back(i);
zx[i] = i;
}
for(auto j : pri){
if (j > n / i)break;//防止 i * j 炸 int
isp[i * j] = false;
zx[i * j] = j;
if (i % j == 0)break;//每次只用最小质因子筛
}
}
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n;
isp[0] = isp[1] = false;
isp[2] = true;
ols();
for(auto i : pri){
cout << i << " ";
}
cout << "\n";
for(int i = 2;i <= n;i ++){
cout << zx[i] << " ";
}
return 0;
}
背包问题
完全背包
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n,m,w[N],v[N],f[N];
//n 物品数量,m 背包容量,v[i] 第 i 个物品体积,w[i] 第 i 个物品价值
//f[i][j] 选到第 i 件物品,背包此时容量为 j 的最大价值
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
for(int i = 1;i <= n;i ++){
cin >> v[i] >> w[i];
}
for(int i = 1;i <= n;i ++){
for(int j = w[i];j <= m;j ++){
f[j] = max(f[j - w[i]] + v[i],f[j]);
}
}
return 0;
}
01背包
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n,m,w[N],v[N],f[N];
//n 物品数量,m 背包容量,v[i] 第 i 个物品体积,w[i] 第 i 个物品价值
//f[i][j] 选到第 i 件物品,背包此时容量为 j 的最大价值
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
for(int i = 1;i <= n;i ++){
cin >> v[i] >> w[i];
}
for(int i = 1;i <= n;i ++){
for(int j = m;j >= w[i];j --){
f[j] = max(f[j - w[i]] + v[i],f[j]);
}
}
return 0;
}
上升下降子序列
int cnt = 0;
for(int i = 1;i <= n;i ++){
if (a[i] >= sheng[cnt]){
sheng[++cnt] = a[i];
}else{
sheng[upper_bound(sheng + 1,sheng + 1 + cnt,a[i]) - sheng] = a[i];
}
}
cout << cnt;
//最长非下降子序列模版
int cnt = 0;
for(int i = 1;i <= n;i ++){
if (b[i] >= jiang[cnt]){
jiang[++cnt] = b[i];
}else{
jiang[upper_bound(jiang + 1,jiang + 1 + cnt,b[i]) - jiang] = b[i];
}
}
cout << cnt;
//最长非上升子序列模版
int cnt = 0;
for(int i = 1;i <= n;i ++){
if (a[i] > sheng[cnt]){
sheng[++cnt] = a[i];
}else{
sheng[lower_bound(sheng + 1,sheng + 1 + cnt,a[i]) - sheng] = a[i];
}
}
cout << cnt;
//最长上升子序列模版
int cnt = 0;
for(int i = 1;i <= n;i ++){
if (b[i] > jiang[cnt]){
jiang[++cnt] = b[i];
}else{
jiang[lower_bound(jiang + 1,jiang + 1 + cnt,b[i]) - jiang] = b[i];
}
}
cout << cnt;
//最长下降子序列模版
for(int i = 1;i <= n;i ++){
cin >> a[i];
}
for(int i = 1;i <= n;i ++){
b[i] = a[n-i+1];
}
//b[ ]为a[ ]的倒序数组
归并排序
#include<bits/stdc++.h>
using namespace std;
int n;
int a[100005];
int b[100005];
void merge(int l,int r,int m){
int i = l,j = m + 1;
int cnt = l;
while(i <= m and j <= r){
if (a[i] < a[j]){
b[cnt] = a[i];
i ++;
}else{
b[cnt] = a[j];
j ++;
}
cnt ++;
}
while(i <= m){
b[cnt] = a[i];
i ++;
cnt ++;
}
while(j <= r){
b[cnt] = a[j];
j ++;
cnt ++;
}
for(int k = l;k <= r;k ++){
a[k] = b[k];
}
}
void bsort(int l,int r){
if (l >= r)return;
int m = (l + r) / 2;
bsort(l,m);
bsort(m + 1,r);
merge(l,r,m);//合并左右部分
}
int main(){
cin >> n;
for(int i = 1;i <= n;i ++){
cin >> a[i];
}
bsort(1,n);
for(int i = 1;i <= n;i ++){
cout << a[i] << " ";
}
return 0;
}
最短路
floyd
#include<bits/stdc++.h>
using namespace std;
const int N=105;
int n,m,dis[N][N];
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
memset(dis,0x3f,sizeof(dis));
for(int i = 1;i <= m;i ++){
int u,v,d;
cin >> u >> v >> d;
dis[u][v] = min(dis[u][v],d);
dis[v][u] = min(dis[v][u],d);
}
for(int i = 1;i <= n;i ++)dis[i][i] = 0;
for(int k = 1;k <= n;k ++){
for(int i = 1;i <= n;i ++){
for(int j = 1;j <= n;j ++){
dis[i][j] = min(dis[i][j],dis[i][k] + dis[k][j]);
}
}
}
for(int i = 1;i <= n;i ++){
for(int j = 1;j <= n;j ++){
cout << dis[i][j] << " ";
}
cout << "\n";
}
return 0;
}
dijkstra 朴素
#include<bits/stdc++.h>
using namespace std;
struct node{
int y,v;
node(int _y,int _v){
y = _y,v = _v;
}
};
vector<node>edge[5003];
int n,m,k,dist[5003];
bool b[5003];
inline void dijkstra(int s,int t){
memset(b,false,sizeof(b));
memset(dist,127,sizeof(dist));
dist[s]=0;
for(;;){
int x = -1;
for(int i = 1;i <= n;i ++){
if (!b[i] and dist[i] < 1 << 30 ){
if (x == -1 or dist[i] < dist[x]){
x = i;
}
}
}
if (x == t or x == -1){
break;
}
b[x] = true;
for(auto i : edge[x]){
dist[i.y] = min(dist[i.y],dist[x] + i.v);
}
}
if (dist[t] < 1 << 30){
cout << dist[t] << "\n";
}else{
cout << -1 << "\n";
}
}
int main(){
cin >> n >> m >> k;
for(int i = 1;i <= m;i ++){
int x,y,z;
cin >> x >> y >> z;
edge[x].push_back(node(y,z));
}
for(int i = 1;i <= k;i ++){
int s,t;
cin >> s >> t;
dijkstra(s,t);
}
return 0;
}
dijkstra 堆优化
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n, q;
struct node{ int to, d; };
vector<node> e[N];
inline void dijkstra(int s, int t){
static int dist[N];
static bool vis[N];
memset(dist, 0x3f, sizeof(int ) * (n + 1));
memset(vis , 0 , sizeof(bool) * (n + 1));
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>> pq;
dist[s] = 0;
pq.push({0, s});
while(!pq.empty()){
pair<int,int> p = pq.top(); pq.pop();
int d = p.first, u = p.second;
if(vis[u]) continue;
vis[u] = true;
if(u == t) break;
for(auto &nx : e[u]){
int v = nx.to, w = nx.d;
if(dist[v] > d + w){
dist[v] = d + w;
pq.push({dist[v], v});
}
}
}
cout << dist[t] << '\n';
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> q;
for(int i = 1; i < n; i++){
int u, v, w;
cin >> u >> v >> w;
e[u].push_back({v, w});
e[v].push_back({u, w});
}
while(q--){
int from, to;
cin >> from >> to;
dijkstra(from, to);
}
return 0;
}
哈希
字符串哈希
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int P=0xccf54188 - 1;
int n;
int mi[2005],cnt;
unordered_map<int,bool>mp;
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n;
mi[0] = 1;
for(int i = 1;i <= 2000; i++){
mi[i] = mi[i - 1] * 127 % P;
}
for(int i = 1;i <= n; i++){
string s;
int key = 0;
cin >> s;
for(int j = 0;j < s.size(); j++){
key += (s[j] - '0') * mi[j];
key %= P;
}
if (mp[key] == false)cnt++;
mp[key] = true;
}
cout << cnt;
return 0;
}
哈希表
拉链法
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int T = 1e7 + 19;
const int N = 5e6 + 5;
int h[T],ne[N],idx = 0,n;
ull key[N],val[N],x,y,ans;
struct hash{
inline void init(){
memset(h,-1,sizeof(h));
}
ull find(ull x){
int k = (int)(x % T);
for(int i = h[k];i != -1;i = ne[i]){
if (key[i] == x){
return val[i];
}
}
return 0;
}
inline void insert(ull x,ull y){
int k = (int)(x % T);
for(int i = h[k];i != -1;i = ne[i]){
if (key[i] == x){
val[i] = y;
return;
}
}
key[idx] = x;
val[idx] = y;
ne[idx] = h[k];
h[k] = idx++;
}
}hh;
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n;
hh.init();
for(int i = 1;i <= n;i++){
cin >> x >> y;
ans += (ull)i * hh.find(x);
hh.insert(x,y);
}
cout << ans;
return 0;
}
开放寻址法
#include<bits/stdc++.h>
using namespace std;
#define int unsigned long long
const int N = 1e7+19;
int t,x,y,ans,i = 1;
struct hash_table{
int h[N],val[N];
bool used[N];
inline void init(){
memset(used,0,sizeof(used));
return;
}
inline int find(int x){
int k = x%N;
while(used[k] and h[k] != x){
k++;
if (k == N)k = 0;
}
return k;
}
inline int query(int x){
int k = find(x);
return used[k] ? val[k] : 0;
}
inline void insert(int x,int y){
int k = find(x);
used[k] = 1;
h[k] = x;
val[k] = y;
return;
}
}hs;
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> t;
hs.init();
while(t--){
cin >> x >> y;
ans += i * hs.query(x);
hs.insert(x,y);
i++;
}
cout << ans;
return 0;
}
单调栈
#include<bits/stdc++.h>
using namespace std;
const int N = 3e6+5;
int n,a[N],ans[N];
stack<int>st;
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n;
for(int i = 1;i <= n;i++){
cin >> a[i];
}
for(int i = 1;i <= n;i++){
while(!st.empty() and a[st.top()] < a[i]){
ans[st.top()] = i;
st.pop();
}
st.push(i);
}
for(int i = 1;i <= n;i++){
cout << ans[i] << " ";
}
return 0;
}
单调队列
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+5;
deque<int>dq;
int n,k,a[N],minn[N],maxn[N];
signed main(){
cin >> n >> k;
for(int i = 1;i <= n;i++){
cin >> a[i];
}
for(int i = 1;i <= n;i++){
if (!dq.empty() and i - dq.front() + 1 > k)dq.pop_front();
while(!dq.empty() and a[dq.back()] > a[i])dq.pop_back();
dq.push_back(i);
if (i - k >= 0){
minn[i - k + 1] = dq.front();
}
}
dq.clear();
for(int i = 1;i <= n;i++){
if (!dq.empty() and i - dq.front() + 1 > k)dq.pop_front();
while(!dq.empty() and a[dq.back()] < a[i])dq.pop_back();
dq.push_back(i);
if (i - k >= 0){
maxn[i - k + 1] = dq.front();
}
}
for(int i = 1;i <= n - k + 1;i++){
cout << a[minn[i]] << " ";
}
cout << "\n";
for(int i = 1;i <= n - k + 1;i++){
cout << a[maxn[i]] << " ";
}
return 0;
}
树状数组
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5e5 + 5;
int n,m,a[N],s[N];
inline int lowbit(int x){
return x & -x;
}
inline void update(int pos,int val){
for(int i = pos;i <= n;i += lowbit(i)){
s[i] += val;
}
}
inline int query(int pos){
int ans = 0;
for(int i = pos;i;i -= lowbit(i)){
ans += s[i];
}
return ans;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
for(int i = 1;i <= n;i++){
cin >> a[i];
update(i,a[i]);
}
while(m--){
int op;
cin >> op;
if (op == 1){
int pos,val;
cin >> pos >> val;
update(pos,val);
}else{
int l,r;
cin >> l >> r;
cout << query(r) - query(l-1) << "\n";
}
}
return 0;
}
线段树
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ls (rt << 1)
#define rs (rt << 1 | 1)
const int N = 1e5 + 5;
struct tree{
int l,r,sum,lazy;
}t[N << 2];
int n,m,a[N];
inline void pushup(int rt){
t[rt].sum = t[ls].sum + t[rs].sum;
}
inline void apply(int rt,int lz){
t[rt].sum += lz * (t[rt].r - t[rt].l + 1);
t[rt].lazy += lz;
}
inline void pushdown(int rt){
int lz = t[rt].lazy;
t[rt].lazy = 0;
apply(ls,lz);
apply(rs,lz);
}
inline void build(int rt,int l,int r){
t[rt].l = l,t[rt].r = r;
if (l == r){
t[rt].sum = a[l];
return;
}
int mid = (l + r) >> 1;
build(ls,l,mid);
build(rs,mid+1,r);
pushup(rt);
}
inline void update(int rt,int l,int r,int val){
if (l <= t[rt].l and t[rt].r <= r){
apply(rt,val);
return;
}
pushdown(rt);
int mid = (t[rt].l + t[rt].r) >> 1;
if (l <= mid)update(ls,l,r,val);
if (mid < r)update(rs,l,r,val);
pushup(rt);
}
inline int query(int rt,int l,int r){
if (l <= t[rt].l and t[rt].r <= r){
return t[rt].sum;
}
pushdown(rt);
int mid = (t[rt].l + t[rt].r) >> 1,ans = 0;
if (l <= mid)ans += query(ls,l,r);
if (mid < r)ans += query(rs,l,r);
return ans;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
for(int i = 1;i <= n;i++){
cin >> a[i];
}
build(1,1,n);
while(m--){
int op;
cin >> op;
if (op == 1){
int x,y,val;
cin >> x >> y >>val;
update(1,x,y,val);
}else{
int l,r;
cin >> l >> r;
cout << query(1,l,r) << "\n";
}
}
return 0;
}
最近公共祖先
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5 + 5;
int n,m,s,d[N],f[N][21];
vector<int>e[N];
inline void dfs(int u,int fa){
d[u] = d[fa] + 1;
f[u][0] = fa;
for(auto v : e[u]){
if (v == fa)continue;
dfs(v,u);
}
}
inline void init(){
for(int j = 1;j <= 20;j++){
for(int i = 1;i <= n;i++){
f[i][j] = f[f[i][j-1]][j-1];
}
}
}
inline int lca(int x,int y){
if (d[x] > d[y])swap(x,y);
for(int i = 20;i >= 0;i--){
if (d[x] <= d[f[y][i]]){
y = f[y][i];
}
}
if (x == y)return x;
for(int i = 20;i >= 0;i--){
if (f[x][i] == f[y][i]){
continue;
}else{
x = f[x][i];
y = f[y][i];
}
}
return f[x][0];
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m >> s;
for(int i = 1;i <= n - 1;i++){
int u,v;
cin >> u >> v;
e[u].push_back(v);
e[v].push_back(u);
}
dfs(s,0);
init();
while(m--){
int x,y;
cin >> x >> y;
cout << lca(x,y) << "\n";
}
return 0;
}
最小生成树
#include<bits/stdc++.h>
using namespace std;
const int N = 5e3 + 5;
int n,m,t,ans,fa[N];
struct node{
int from,to,dis;
};
vector<node>e;
inline bool cmp(node x,node y){
return x.dis < y.dis;
}
inline int find(int x){return (fa[x] == x ? x : fa[x] = find(fa[x]));}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
for(int i = 1;i <= m;i++){
int u,v,dis;
cin >> u >> v >> dis;
e.push_back({u,v,dis});
}
for(int i = 1;i <= n;i++)fa[i] = i;
sort(e.begin(),e.end(),cmp);
for(auto i : e){
int u = i.from,v = i.to,dis = i.dis;
int fu = find(u),fv = find(v);
if (fu != fv){
fa[fu] = fv;
t++;
ans += dis;
}
if (t == n-1){
cout << ans;
exit(0);
}
}
cout<<"orz";
return 0;
}
拓扑排序
#include<bits/stdc++.h>
using namespace std;
const int N = 1e3 + 5;
int n,in[N];
vector<int>e[N];
queue<int>q;
inline void tp(){
while(!q.empty()){
int u = q.front();
q.pop();
cout << u << " ";
for(auto v : e[u]){
in[v]--;
if (in[v] == 0)q.push(v);
}
}
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n;
for(int i = 1;i <= n;i++){
while(1){
int x;
cin >> x;
if (x == 0)break;
e[i].push_back(x);
in[x]++;
}
}
for(int i = 1;i <= n;i++){
if (in[i] == 0)q.push(i);
}
tp();
return 0;
}
tarjan
tarjan 求割点
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int n,m,times,dfn[N],low[N];
bool isgd[N];
vector<int>gd;
vector<int>e[N];
inline void dfs(int u,int fa){
dfn[u] = low[u] = ++times;
int cntson = 0;
bool iscut = false;
for(auto v : e[u]){
if (v == fa)continue;
if (!dfn[v]){
cntson++;
dfs(v,u);
low[u] = min(low[u],low[v]);
if (fa != 0 and low[v] >= dfn[u]){
iscut = true;
}
}else{
low[u] = min(low[u],dfn[v]);
}
}
if (fa == 0 and cntson >= 2){
iscut = true;
}
if (iscut == true and isgd[u] == false){
gd.push_back(u);
isgd[u] = true;
}
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
for(int i = 1;i <= m;i++){
int u,v;
cin >> u >> v;
e[u].push_back(v);
e[v].push_back(u);
}
for(int i = 1;i <= n;i++){
if (!dfn[i]){
dfs(i,0);
}
}
sort(gd.begin(),gd.end());
cout << gd.size() << "\n";
for(auto i : gd){
cout << i << " ";
}
return 0;
}
tarjan 求割边
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5 + 5;
struct node{
int to,id;
};
int n,m,dfn[N],low[N],times;
vector<node>e[N];
vector<int>gb;
inline void dfs(int u,int fa){
dfn[u] = low[u] = ++times;
for(auto i : e[u]){
int v = i.to;
if (v == fa)continue;
if (!dfn[v]){
dfs(v,u);
low[u] = min(low[u],low[v]);
if (low[v] > dfn[u])gb.push_back(i.id);
}else{
low[u] = min(low[u],dfn[v]);
}
}
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
for(int i = 1;i <= m;i++){
int u,v;
cin >> u >> v;
e[u].push_back({v,i});
e[v].push_back({u,i});
}
for(int i = 1;i <= n;i++){
if (!dfn[i]){
dfs(i,0);
}
}
cout << gb.size() << "\n";
sort(gb.begin(),gb.end());
for(auto i : gb){
cout << i << " ";
}
return 0;
}
tarjan 求边双连通分量
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5+5;
int n,m,dfn[N],low[N],times;
struct node{
int to,id;
};
vector<node>e[N];
vector<vector<int>>ans;
stack<int>st;
inline void dfs(int u,int lst){
dfn[u] = low[u] = ++times;
st.push(u);
for(auto i : e[u]){
int v = i.to,nxt = i.id;
if (nxt == (lst^1))continue;
if (!dfn[v]){
dfs(v,nxt);
low[u] = min(low[u],low[v]);
}else{
low[u] = min(low[u],dfn[v]);
}
}
if (dfn[u] == low[u]){
vector<int>res;
res.push_back(u);
while(st.top() != u){
res.push_back(st.top());
st.pop();
}
st.pop();
ans.push_back(res);
}
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
for(int i = 1;i <= m;i++){
int u,v;
cin >> u >> v;
e[u].push_back({v,i << 1});
e[v].push_back({u,i << 1|1});
}
for(int i = 1;i <= n;i++){
if (!dfn[i]){
dfs(i,0);
}
}
cout << ans.size() << "\n";
for(auto i : ans){
cout << i.size() << " ";
for(auto j : i)cout << j << " ";
cout << "\n";
}
return 0;
}
tarjan 求点双连通分量
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5+5;
const int M = 2e6+5;
int n,m,dfn[N],low[N],times;
vector<int>e[M];
vector<vector<int>>ans;
stack<int>st;
inline void dfs(int u,int fa){
dfn[u] = low[u] = ++times;
st.push(u);
if (fa == 0 and e[u].empty()){
ans.push_back({u});
return;
}
for(auto v : e[u]){
if (v == fa)continue;
if (!dfn[v]){
dfs(v,u);
low[u] = min(low[u],low[v]);
if (low[v] >= dfn[u]){
vector<int>res;
int topp;
do{
topp = st.top();
st.pop();
res.push_back(topp);
}while(topp != v);
res.push_back(u);
ans.push_back(res);
}
}else{
low[u] = min(low[u],dfn[v]);
}
}
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
for(int i = 1;i <= m;i++){
int u,v;
cin >> u >> v;
if (u == v)continue;
e[u].push_back(v);
e[v].push_back(u);
}
for(int i = 1;i <= n;i++){
if (!dfn[i]){
times = 0;
dfs(i,0);
}
}
cout << ans.size() << "\n";
for(auto i : ans){
cout << i.size() << " ";
for(auto j : i)cout << j << " ";
cout << "\n";
}
return 0;
}
tarjan 求强连通分量
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
int n,m,a[N];
vector<int>e[N];
vector<int>g[N];
int dfn[N],low[N],times,belong[N],from[N],to[N],dp[N],in[N];
bitset<N>ins;
stack<int>st;
inline void tarjan(int u){
dfn[u] = low[u] = ++times;
st.push(u);
ins[u] = true;
for(auto v : e[u]){
if (!dfn[v]){
tarjan(v);
low[u] = min(low[u],low[v]);
}else if(ins[v]){
low[u] = min(low[u],dfn[v]);
}
}
if (low[u] == dfn[u]){
int topp;
do{
topp = st.top();
st.pop();
belong[topp] = u;
ins[topp] = false;
if (topp != u) a[u] += a[topp];
}while(u != topp);
}
}
inline void tp(){
queue<int>q;
for(int i = 1;i <= n;i++){
if (i == belong[i] and in[i] == 0){
q.push(i);
dp[i] = a[i];
}
}
while(!q.empty()){
int u = q.front();
q.pop();
for(auto v:g[u]){
dp[v] = max(dp[v],dp[u]+a[v]);
if (--in[v] == 0)q.push(v);
}
}
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
for(int i = 1;i <= n;i++)cin >> a[i];
for(int i = 1;i <= m;i++){
int u,v;
cin >> u >> v;
e[u].push_back(v);
from[i] = u,to[i] = v;
}
for(int i = 1;i <= n;i++){
if (!dfn[i])tarjan(i);
}
for(int i = 1;i <= m;i++){
int x = belong[from[i]],y = belong[to[i]];
if (x != y){
g[x].push_back(y);
in[y]++;
}
}
tp();
int ans = -1;
for(int i = 1;i <= n;i++){
ans = max(ans,dp[i]);
}
cout << ans;
return 0;
}
树链剖分
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ls (rt << 1)
#define rs (rt << 1 | 1)
const int N = 1e5 + 5;
int n,m,mod,r,a[N];
vector<int>e[N];
int d[N],f[N],siz[N],son[N];
int id[N],w[N],top[N],times;
struct tree{
int l,r;
ll sum,lazy;
}t[N << 2];
inline void dfs1(int u,int fa){
d[u] = d[fa] + 1;
f[u] = fa;
siz[u] = 1;
int maxson = -1;
for(auto v:e[u]){
if (v == fa)continue;
dfs1(v,u);
siz[u] += siz[v];
if (siz[v] > maxson){
maxson = siz[v];
son[u] = v;
}
}
}
inline void dfs2(int u,int topf){
id[u] = ++times;
w[times] = a[u];
top[u] = topf;
if (son[u] == 0)return;
dfs2(son[u],topf);
for(auto v:e[u]){
if (v == f[u] or v == son[u])continue;
dfs2(v,v);
}
}
inline void pushup(int rt){
t[rt].sum = t[ls].sum + t[rs].sum;
t[rt].sum %= mod;
}
inline void pushdown(int rt){
if (t[rt].lazy){
ll lz = t[rt].lazy;
t[rt].lazy = 0;
t[ls].lazy += lz;
t[rs].lazy += lz;
t[ls].sum += lz * (t[ls].r - t[ls].l + 1);
t[rs].sum += lz * (t[rs].r - t[rs].l + 1);
t[ls].lazy %= mod;
t[rs].lazy %= mod;
t[ls].sum %= mod;
t[rs].sum %= mod;
}
}
inline void build(int rt,int l,int r){
t[rt].l = l,t[rt].r = r;
if (l == r){
t[rt].sum = w[l];
return;
}
int mid = (l + r) >> 1;
build(ls,l,mid);
build(rs,mid + 1,r);
pushup(rt);
}
inline void update(int rt,int l,int r,int val){
if (l <= t[rt].l and t[rt].r <= r){
t[rt].lazy += val;
t[rt].sum += val * (t[rt].r - t[rt].l + 1);
t[rt].lazy %= mod;
t[rt].sum %= mod;
return;
}
pushdown(rt);
int mid = (t[rt].l + t[rt].r) >> 1;
if (l <= mid)update(ls,l,r,val);
if (mid < r)update(rs,l,r,val);
pushup(rt);
}
inline ll query(int rt,int l,int r){
if (l <= t[rt].l and t[rt].r <= r){
t[rt].sum %= mod;
return t[rt].sum;
}
pushdown(rt);
int mid = (t[rt].l+t[rt].r) >> 1;
ll ans = 0;
if (l <= mid)ans += query(ls,l,r);
if (mid < r)ans += query(rs,l,r);
ans %= mod;
return ans;
}
inline void range_add1(int x,int y,int val){
val %= mod;
while(top[x] != top[y]){
if (d[top[x]] < d[top[y]])swap(x,y);
update(1,id[top[x]],id[x],val);
x = f[top[x]];
}
if (d[x] > d[y])swap(x,y);
update(1,id[x],id[y],val);
}
inline ll range_ask1(int x,int y){
ll ans = 0;
while(top[x] != top[y]){
if (d[top[x]] < d[top[y]])swap(x,y);
ans += query(1,id[top[x]],id[x]);
ans %= mod;
x = f[top[x]];
}
if (d[x] > d[y])swap(x,y);
ans += query(1,id[x],id[y]);
ans %= mod;
return ans;
}
inline void range_add2(int x,int val){
val %= mod;
update(1,id[x],id[x] + siz[x] - 1,val);
}
inline ll range_ask2(int x){
ll ans = 0;
ans += query(1,id[x],id[x] + siz[x] - 1);
ans %= mod;
return ans;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m >> r >> mod;
for(int i = 1;i <= n;i++){
cin >> a[i];
a[i] %= mod;
}
for(int i = 1;i <= n - 1;i++){
int u,v;
cin >> u >> v;
e[u].push_back(v);
e[v].push_back(u);
}
dfs1(r,0);
dfs2(r,r);
build(1,1,n);
while(m--){
int op;
cin >> op;
if (op == 1){
int x,y,z;
cin >> x >> y >> z;
range_add1(x,y,z);
}else if(op == 2){
int x,y;
cin >> x >> y;
cout << range_ask1(x,y) << '\n';
}else if(op == 3){
int x,z;
cin >> x >> z;
range_add2(x,z);
}else{
int x;
cin >> x;
cout << range_ask2(x) << "\n";
}
}
return 0;
}
KMP
#include<bits/stdc++.h>
using namespace std;
string s,t;
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> s >> t;
int n = s.size(),m = t.size();
s = ' ' + s,t = ' ' + t;
vector<int>nxt(m+1,0);
for(int i = 2,j = 0;i <= m;i++){
while(j > 0 and t[i] != t[j + 1])j = nxt[j];
if (t[i] == t[j + 1])j++;
nxt[i] = j;
}
for(int i = 1,j = 0;i <= n;i++){
while(j > 0 and s[i] != t[j + 1])j = nxt[j];
if (s[i] == t[j + 1])j++;
if (j == m){
cout << i - m + 1 << "\n";
}
}
for(int i = 1;i < nxt.size();i++)cout << nxt[i] << " ";
return 0;
}
AC 自动机
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
int n,trie[N][26],fail[N],val[N],idx;
inline void insert(string s){
int len = s.size(),p = 0;
for(int i = 0;i < len;i++){
int c = s[i] - 'a';
if (!trie[p][c])trie[p][c] = ++idx;
p = trie[p][c];
}
val[p]++;
}
inline void build(){
queue<int>q;
for(int c = 0;c < 26;c++){
if (trie[0][c]){
fail[trie[0][c]] = 0;
q.push(trie[0][c]);
}
}
while(!q.empty()){
int u = q.front();
q.pop();
for(int c = 0;c < 26;c++){
int v = trie[u][c];
if (v){
fail[v] = trie[fail[u]][c];
q.push(v);
}else{
trie[u][c] = trie[fail[u]][c];
}
}
}
}
inline int query(string s){
int len = s.size(),p = 0,ans = 0;
for(int i = 0;i < len;i++){
p = trie[p][s[i]-'a'];
for(int t = p;t and val[t] != -1;t = fail[t]){
ans += val[t];
val[t] = -1;
}
}
return ans;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n;
for(int i = 1;i <= n;i++){
string s;
cin >> s;
insert(s);
}
build();
string s;
cin >> s;
cout << query(s);
return 0;
}