矩阵快速幂
参考题目:https://codeforces.com/problemset/problem/678/D
#include<bits/stdc++.h>
#define ios std::ios::sync_with_stdio(false)
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,n,a) for (int i=n;i>=a;i--)
#define int long long
#define ll long long
#define MOD 1000000007
using namespace std;
const int MAXN = 10;
struct Matrix
{
ll mat[MAXN][MAXN];
};
Matrix P;
Matrix I; //单位矩阵
Matrix Mul_Matrix(Matrix a, Matrix b , ll mod)
{
Matrix c;
for(int i = 0 ; i < MAXN ; i ++)
for(int j = 0 ; j < MAXN ; j ++)
{
c.mat[i][j] = 0;
for(int k = 0 ; k < MAXN ; k ++)
{
c.mat[i][j] += (a.mat[i][k] * b.mat[k][j]) % mod;
c.mat[i][j] %= mod;
}
}
return c;
}
Matrix pow_mod_Matrix(Matrix P , ll n , ll mod)
{
Matrix ans = I, b = P;
while(n)
{
if(n & 1) ans = Mul_Matrix(ans , b , mod);
n >>= 1;
b = Mul_Matrix(b , b , mod);
}
return ans;
}
void Matrix_init()
{
for(int i = 0 ; i < MAXN ; i ++) I.mat[i][i] = 1;
}
signed main()
{
ios;
int a , b , n , x;
cin >> a >> b >> n >> x;
Matrix_init();
{
P.mat[0][0] = a, P.mat[0][1] = 0;
P.mat[1][0] = 1, P.mat[1][1] = 1;
Matrix res = pow_mod_Matrix(P , n , MOD);
ll ans = x * res.mat[0][0] + b * res.mat[1][0];
ans = (ans % MOD + MOD) % MOD;
cout << ans << '\n';
}
return 0;
}
Dijkstra堆优化
参考题目:https://www.luogu.com.cn/problem/P4779
#include<bits/stdc++.h>
#define int long long
#define rep(i , a , b) for(int i = a ; i <= b ; i ++)
using namespace std;
const int inf = 0x3f3f3f3f;
const int N = 2e5 + 10;
struct node{
int dis , pos;
bool operator <( const node &x )const{
return x.dis < dis;
}
};
struct Edge{
int to , dis , nex;
}edge[N << 1];
int head[N], dis[N] , tot , vis[N] , n , m , s;
inline void add_edge(int u , int v , int d)
{
edge[++ tot].dis = d;
edge[tot].to = v;
edge[tot].nex = head[u];
head[u] = tot;
}
inline void dijkstra(int s)
{
memset(dis , inf , sizeof(dis)) ;
dis[s] = 0;
priority_queue <node> que;
que.push(node{0, s});
while(!que.empty())
{
node tmp = que.top();
que.pop();
int u = tmp.pos, d = tmp.dis;
if(vis[u]) continue;
vis[u] = 1;
for(int i = head[u] ; i ; i = edge[i].nex)
{
int v = edge[i].to;
if(dis[v] > dis[u] + edge[i].dis)
{
dis[v] = dis[u] + edge[i].dis;
if(!vis[v]) que.push(node{dis[v] , v});
}
}
}
}
signed main()
{
ios::sync_with_stdio(false);
cin >> n >> m >> s;
rep(i , 1 , m)
{
int u , v , w;
cin >> u >> v >> w;
add_edge(u , v , w);
}
dijkstra(s);
rep(i , 1 , n) cout << dis[i] << " ";
cout << '\n';
return 0;
}
Dijkstra配对堆
#include<bits/stdc++.h>
#include<ext/pb_ds/priority_queue.hpp>
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,n,a) for (int i=n;i>=a;i--)
#define il inline
using namespace std;
using namespace __gnu_pbds;
const int inf (0x3f3f3f3f);
typedef __gnu_pbds::priority_queue< pair<int,int> ,greater< pair<int,int> >,pairing_heap_tag > heap;
template<typename T>void read(T &res){bool flag=false;char ch;while(!isdigit(ch=getchar()))(ch=='-')&&(flag=true);
for(res=ch-48;isdigit(ch=getchar());res=(res<<1)+(res<<3)+ch - 48);flag&&(res=-res);}
template<typename T>void Out(T x){if(x<0)putchar('-'),x=-x;if(x>9)Out(x/10);putchar(x%10+'0');}
const int N = 2e5 + 10;
heap que;
heap::point_iterator id[N];
struct Edge{
int nex , to , w;
}edge[N << 1];
int head[N] , tot;
il void add_edge(int u , int v , int w)
{
edge[++ tot].nex = head[u];
edge[tot].to = v;
edge[tot].w = w;
head[u] = tot;
}
int n , m , s , dis[N];
il void dij(int st)
{
memset(dis , inf , sizeof(dis));
dis[st] = 0;
id[st] = que.push(make_pair(0 , st));
while(!que.empty())
{
int u = que.top().second;
que.pop();
for(int i = head[u] ; i ; i = edge[i].nex)
{
int v = edge[i].to ;
int w = edge[i].w ;
if(w + dis[u] < dis[v])
{
dis[v] = dis[u] + edge[i].w;
if(id[edge[i].to] != 0) que.modify(id[v] , make_pair(dis[v] , v));
else id[v] = que.push(make_pair(dis[v] , v));
}
}
}
}
signed main()
{
read(n) , read(m) , read(s);
rep(i , 1 , m)
{
int u , v , w;
read(u) , read(v) , read(w);
add_edge(u , v , w);
}
dij(s);
rep(i , 1 , n) Out(dis[i]) , putchar(' ');
return 0;
}
Manacher
参考题目:https://www.luogu.com.cn/problem/P3805
#include<bits/stdc++.h>
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,n,a) for (int i=n;i>=a;i--)
using namespace std;
const int N = 3e7 + 10;
int pa[N];
string a ;
int Manacher(string a , int *p)
{
string t = "$#";
for(auto i : a) t += i , t += '#';
int mx = 0 , id = 0 ;
int len = t.size() , ans = 0;
for(int i = 1 ; i < len ; i ++)
{
p[i] = mx > i ? min(p[2 * id - i] , mx - i) : 1;
while(t[i + p[i]] == t[i - p[i]]) p[i] ++ ;
if(mx < i + p[i]) mx = i + p[i] , id = i;
ans = max(ans , p[i] - 1);
}
return ans;
}
signed main()
{
ios::sync_with_stdio(false) , cin.tie(0) , cout.tie(0);
cin >> a ;
cout << Manacher(a , pa) << '\n';
return 0;
}
主席树
参考题目:https://www.luogu.com.cn/problem/P3834
#include<bits/stdc++.h>
#define rep(i,a,n) for (int i=a;i<=n;i++)
using namespace std;
const int N = 3e5 + 10;
struct Chairman_Tree{
int l , r , sum;
}Ctree[N << 5];
vector<int>vec;
int root[N] , a[N] , Ctot;
void update(int l , int r , int pre , int &now , int pos)
{
Ctree[++ Ctot] = Ctree[pre];
Ctree[Ctot].sum ++ ;
now = Ctot;
if(l == r) return ;
int mid = l + r >> 1;
if(pos <= mid) update(l , mid , Ctree[pre].l , Ctree[now].l , pos);
else update(mid + 1 , r , Ctree[pre].r , Ctree[now].r , pos);
}
int query(int l , int r , int L , int R , int k)
{
if(l == r) return l ;
int mid = l + r >> 1;
int cha = Ctree[Ctree[R].l].sum - Ctree[Ctree[L].l].sum;
if(cha >= k) return query(l , mid , Ctree[L].l , Ctree[R].l , k);
else return query(mid + 1 , r , Ctree[L].r , Ctree[R].r , k - cha);
}
int get_id(int x)
{
return lower_bound(vec.begin() , vec.end() , x) - vec.begin() + 1;
}
signed main()
{
ios::sync_with_stdio(false);
int n , m ;
cin >> n >> m;
rep(i , 1 , n)
{
cin >> a[i];
vec.push_back(a[i]);
}
sort(vec.begin() , vec.end());
vec.erase(unique(vec.begin() , vec.end()) , vec.end()) ;
rep(i , 1 , n)
update(1 , n , root[i - 1] , root[i] , get_id(a[i]));
while(m --)
{
int l , r , k;
cin >> l >> r >> k ;
int pos = query(1 , n , root[l - 1] , root[r] , k);
cout << vec[pos - 1] << '\n' ;
}
return 0;
}
二次剩余
*参考题目:https://www.luogu.com.cn/problem/P5491*
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll w;
struct num
{
ll x, y;
};
num mul(num a, num b, ll p)
{
num ans = {0, 0};
ans.x = ((a.x * b.x % p + a.y * b.y % p * w % p) % p + p) % p;
ans.y = ((a.x * b.y % p + a.y * b.x % p) % p + p) % p;
return ans;
}
ll powwR(ll a, ll b, ll p)
{
ll ans = 1;
while (b)
{
if (b & 1)
ans = 1ll * ans % p * a % p;
a = a % p * a % p;
b >>= 1;
}
return ans % p;
}
ll powwi(num a, ll b, ll p)
{
num ans = {1, 0};
while (b)
{
if (b & 1)
ans = mul(ans, a, p);
a = mul(a, a, p);
b >>= 1;
}
return ans.x % p;
}
ll M_sqrt(ll n, ll p)
{
n %= p;
if (p == 2)
return n;
if (powwR(n, (p - 1) / 2, p) == p - 1)
return -1; //不存在
ll a;
while (1)
{
a = rand() % p;
w = ((a * a % p - n) % p + p) % p;
if (powwR(w, (p - 1) / 2, p) == p - 1)
break;
}
num x = {a, 1};
return powwi(x, (p + 1) / 2, p);
}
signed main()
{
ios::sync_with_stdio(false);
int t;
cin >> t;
while(t --)
{
ll n , p;
cin >> n >> p ;
if(!n)
{
cout << 0 << '\n' ;
continue ;
}
ll ans1 = M_sqrt(n , p) , ans2;
if(ans1 == -1) cout << "Hola!\n";
else
{
ans2 = p - ans1;
if(ans1 > ans2) swap(ans1 , ans2);
if(ans1 == ans2) cout << ans1 << '\n';
else cout << ans1 << " " << ans2 << '\n' ;
}
}
return 0;
}
KMP
参考题目:https://www.luogu.com.cn/problem/P3375
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int nex[N] ;
vector<int>ans;
string s , t;
void get_nex(string s , int *nex)
{
int i = 0 , j = -1 , len = s.size();
nex[i] = j;
while(i < len)
{
while(j != -1 && s[i] != s[j]) j = nex[j];
nex[++ i] = ++ j ;
}
}
void KMP(string s , string t)
{
get_nex(t , nex) ;
int i = 0 , j = 0 , lens = s.size() , lent = t.size();
while(i < lens)
{
while(j != -1 && s[i] != t[j]) j = nex[j];
i ++ , j ++ ;
if(j == lent) ans.push_back(i - lent + 1);
}
}
signed main()
{
ios::sync_with_stdio(false);
cin >> s >> t ;
KMP(s , t);
for(auto i : ans) cout << i << '\n' ;
for(int i = 1 ; i <= t.size() ; i ++ ) cout << nex[i] << " ";
cout << '\n';
return 0;
}
MatrixTree矩阵树——求无向图生成树个数
参考题目:https://www.luogu.com.cn/problem/SP104
#include<bits/stdc++.h>
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,n,a) for (int i=n;i>=a;i--)
#define int long long
#define ll long long
using namespace std;
const int N = 2e2 + 10;
const double eps = 1e-12;
int G[N][N];
int n , m;
int dcmp(int x)
{
if(x <= eps || x >= -eps) return 0;
else return x < 0 ? -1 : 1;
}
void init(int n)
{
rep(i , 0 , n) rep(j , 0 , n) G[i][j] = 0;
}
ll Gauss(int n)
{
ll ans = 1;
rep(i , 1 , n - 1)
{
rep(k , i + 1 , n - 1)
{
while(G[k][i])
{
int d = G[i][i] / G[k][i];
rep(j , i , n - 1) G[i][j] = (G[i][j] - 1LL * d * G[k][j]);
swap(G[i] , G[k]) , ans = -ans;
}
}
ans = 1LL * ans * G[i][i];
}
return ans;
}
signed main()
{
ios::sync_with_stdio(false) , cin.tie(0) , cout.tie(0);
int T = 1;
cin >> T;
while(T --)
{
cin >> n >> m;
init(n);
rep(i , 1 , m)
{
int x , y ;
cin >> x >> y ;
G[x][x] ++ , G[y][y] ++;
G[x][y] -- , G[y][x] --;
}
int tot = Gauss(n);
cout << tot << '\n';
}
return 0;
}
AC自动机—fail树
参考题目:https://www.luogu.com.cn/problem/P5357
#include<bits/stdc++.h>
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,n,a) for (int i=n;i>=a;i--)
#define int long long
#define ll long long
using namespace std;
const int N = 3e5 + 10;
struct Edge{
int nex , to;
}edge[N << 1];
int head[N] , TOT;
void add_edge(int u , int v)
{
edge[++ TOT].nex = head[u] ;
edge[TOT].to = v;
head[u] = TOT;
}
int cnt[N] , fail[N] , num[N];
int tree[N][26];
int tot = 0;
void del(int x)
{
cnt[x] = 0 , fail[x] = 0;
rep(i , 0 , 25) tree[x][i] = 0;
}
void insert(string s , int id)
{
int root = 0;
for(auto i : s)
{
int x = i - 'a';
if(!tree[root][x])
{
tree[root][x] = ++ tot;
del(tot);
}
root = tree[root][x];
}
num[id] = root;
}
void build()
{
queue<int>que;
rep(i , 0 , 25) if(tree[0][i])
{
int v = tree[0][i];
fail[v] = 0;
que.push(v);
}
while(!que.empty())
{
int u = que.front();
que.pop();
rep(i , 0 , 25)
{
if(tree[u][i])
{
int v = tree[u][i];
fail[v] = tree[fail[u]][i];
que.push(v);
}
else tree[u][i] = tree[fail[u]][i];
}
}
}
void query(string s)
{
int p = 0 , res = 0;
for(auto i : s)
{
int x = i - 'a';
p = tree[p][x] ;
cnt[p] ++ ;
}
}
string st[N] , s;
void dfs(int u , int far)
{
for(int i = head[u] ; i ; i = edge[i].nex)
{
int v = edge[i].to ;
if(v == far) continue ;
dfs(v , u);
cnt[u] += cnt[v];
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
int n , T = 1;
cin >> n;
rep(i , 1 , n) cin >> st[i] , insert(st[i] , i);
build();
cin >> s;
query(s);
rep(i , 1 , tot) add_edge(fail[i] , i);
dfs(0 , -1);
rep(i , 1 , n) cout << cnt[num[i]] << '\n';
return 0;
}
参考题目:https://www.luogu.com.cn/problem/P3796
#include<bits/stdc++.h>
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,n,a) for (int i=n;i>=a;i--)
using namespace std;
const int N = 1e6 + 10;
int cnt[N] , fail[N] , num[N];
int tree[N][26];
int tot = 0;
struct Edge{
int nex , to;
}edge[N << 1];
int head[N] , TOT;
void add_edge(int u , int v)
{
edge[++ TOT].nex = head[u] ;
edge[TOT].to = v;
head[u] = TOT;
}
void del(int x)
{
cnt[x] = 0 , fail[x] = 0;
rep(i , 0 , 25) tree[x][i] = 0;
}
void insert(string s , int id)
{
int root = 0;
for(auto i : s)
{
int x = i - 'a';
if(!tree[root][x])
{
tree[root][x] = ++ tot;
del(tot);
}
root = tree[root][x];
}
num[id] = root;
}
void build()
{
queue<int>que;
rep(i , 0 , 25) if(tree[0][i])
{
int v = tree[0][i];
fail[v] = 0;
que.push(v);
}
while(!que.empty())
{
int u = que.front();
que.pop();
rep(i , 0 , 25)
{
if(tree[u][i])
{
int v = tree[u][i];
fail[v] = tree[fail[u]][i];
que.push(v);
}
else tree[u][i] = tree[fail[u]][i];
}
}
}
int query(string s)
{
int p = 0 , res = 0;
for(auto i : s)
{
int x = i - 'a';
p = tree[p][x] ;
int fi = p;
cnt[fi] ++ ;
}
return res;
}
void dfs(int u , int far)
{
for(int i = head[u] ; i ; i = edge[i].nex)
{
int v = edge[i].to;
if(v == far) continue ;
dfs(v , u);
cnt[u] += cnt[v];
}
}
string st[N] , s;
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
int n , T = 1;
while(cin >> n && n)
{
rep(i , 1 , n) cin >> st[i] , insert(st[i] , i);
build();
cin >> s;
query(s);
rep(i , 1 , tot) add_edge(fail[i] , i);
dfs(0 , -1);
int ans = 0;
rep(i , 1 , n) ans = max(ans , cnt[num[i]]);
cout << ans << '\n';
rep(i , 1 , n) if(ans == cnt[num[i]]) {cout << st[i] << '\n';}
del(0);
tot = 0;
memset(head , 0 , sizeof(head)) , TOT = 0;
}
return 0;
}
AC自动机—fail指针乱跳版
参考题目:https://www.luogu.com.cn/problem/P3808
#include<bits/stdc++.h>
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,n,a) for (int i=n;i>=a;i--)
using namespace std;
const int N = 1e6 + 10;
int cnt[N] , fail[N];
int tree[N][26];
int tot = 0;
string s;
void del(int x)
{
cnt[x] = 0 , fail[x] = 0;
rep(i , 0 , 25) tree[x][i] = 0;
}
void insert(string s)
{
int root = 0;
for(auto i : s)
{
int x = i - 'a';
if(!tree[root][x])
{
tree[root][x] = ++ tot;
del(tot);
}
root = tree[root][x];
}
cnt[root] ++ ;
}
void build()
{
queue<int>que;
rep(i , 0 , 25) if(tree[0][i])
{
int v = tree[0][i];
fail[v] = 0;
que.push(v);
}
while(!que.empty())
{
int u = que.front();
que.pop();
rep(i , 0 , 25)
{
if(tree[u][i])
{
int v = tree[u][i];
fail[v] = tree[fail[u]][i];
que.push(v);
}
else tree[u][i] = tree[fail[u]][i];
}
}
}
int query(string s)
{
int p = 0 , res = 0;
for(auto i : s)
{
int x = i - 'a';
p = tree[p][x] ;
int fi = p;
while(fi && cnt[fi] != -1)
{
res += cnt[fi];
cnt[fi] = -1;
fi = fail[fi];
}
}
return res;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
int n , T = 1;
while(T --)
{
cin >> n;
rep(i , 1 , n) cin >> s , insert(s);
build();
cin >> s;
cout << query(s) << '\n';
del(0);
tot = 0;
}
return 0;
}
网络流—预流推进HLPP
参考题目:https://www.luogu.com.cn/problem/P4722
#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int inf = INT_MAX;
const ll INF = (0x3f3f3f3f3f3f3f3fll);
const int maxn = 1.2e3 + 5;
struct HLPP
{
struct Edge
{
int v, rev;
ll cap;
};
int n, sp, tp, lim, ht, lcnt;
ll exf[maxn];
vector<Edge> G[maxn];
vector<int> hq[maxn], gap[maxn], h, sum;
void init(int nn, int s, int t)
{
sp = s, tp = t, n = nn, lim = n + 1, ht = lcnt = 0;
for(int i = 1; i <= n; ++i) G[i].clear(), exf[i] = 0;
}
void add_edge(int u, int v, ll cap)
{
G[u].push_back( {v, (int)(G[v].size()) , cap});
G[v].push_back( {u, (int)(G[u].size()) - 1, 0});
}
void update(int u, int nh)
{
++lcnt;
if(h[u] != lim) --sum[h[u]];
h[u] = nh;
if(nh == lim) return;
++sum[ht = nh];
gap[nh].push_back(u);
if(exf[u] > 0) hq[nh].push_back(u);
}
void relabel()
{
queue<int> q;
for(int i = 0; i <= lim; ++i) hq[i].clear(), gap[i].clear();
h.assign(lim, lim), sum.assign(lim, 0), q.push(tp);
lcnt = ht = h[tp] = 0;
while(!q.empty())
{
int u = q.front();
q.pop();
for(Edge &e : G[u]) if(h[e.v] == lim && G[e.v][e.rev].cap) update(e.v, h[u] + 1), q.push(e.v);
ht = h[u];
}
}
void push(int u, Edge &e)
{
if(!exf[e.v]) hq[h[e.v]].push_back(e.v);
ll df = min(exf[u], e.cap);
e.cap -= df, G[e.v][e.rev].cap += df;
exf[u] -= df, exf[e.v] += df;
}
void discharge(int u)
{
int nh = lim;
if(h[u] == lim) return;
for(Edge &e : G[u])
{
if(!e.cap) continue;
if(h[u] == h[e.v] + 1)
{
push(u, e);
if(exf[u] <= 0) return;
}
else if(nh > h[e.v] + 1) nh = h[e.v] + 1;
}
if(sum[h[u]] > 1) update(u, nh);
else
{
for( ; ht >= h[u]; gap[ht--].clear())
for(int &i : gap[ht]) update(i, lim);
}
}
ll hlpp()
{
exf[sp] = INF, exf[tp] = -INF, relabel();
for(Edge &e : G[sp]) push(sp, e);
for( ; ~ht; --ht)
{
while(!hq[ht].empty())
{
int u = hq[ht].back();
hq[ht].pop_back();
discharge(u);
if(lcnt > (n << 2)) relabel();
}
}
return exf[tp] + INF;
}
}hp;
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
int n, m, s, t, u, v, w;
cin >> n >> m >> s >> t;
hp.init(n, s, t);
while(m --)
{
cin >> u >> v >> w;
hp.add_edge(u, v, w);
}
cout << hp.hlpp() << '\n';
return 0;
}
网络流—dinic
参考题目:https://www.luogu.com.cn/problem/P3376
#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
#define ios std::ios::sync_with_stdio(false)
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,n,a) for (int i=n;i>=a;i--)
#define int long long
#define ll long long
using namespace std;
const ll INF (0x3f3f3f3f3f3f3f3fll);
const int inf = 0x3f3f3f3f3f;
const int N = 3e5 + 10;
struct Edge{
int nex , to;
}edge[N << 1];
int head[N] , TOT;
void add_edge(int u , int v)
{
edge[++ TOT].nex = head[u] ;
edge[TOT].to = v;
head[u] = TOT;
}
const int Max = 1e5 + 10;
struct Dinic
{
struct Edge
{
int to, nex, flow; //flow记录这条边当前的边残量
} edge[Max << 1];
int n, m, s, t;
int head[Max], TOT;
int dis[Max] , cur[Max];
void init(int nn , int ss , int tt)
{
this->n = nn , this->s = ss , this->t = tt;
TOT = 1;
for(int i = 0 ; i <= nn + 1 ; i ++) head[i] = 0;
}
void add_edge(int u , int v , int flow)
{
edge[++ TOT].nex = head[u];
edge[TOT].to = v;
edge[TOT].flow = flow;
head[u] = TOT;
edge[++ TOT].nex = head[v];
edge[TOT].to = u;
edge[TOT].flow = 0;
head[v] = TOT;
}
bool bfs() //判断图是否连通
{
queue<int>que;
memset(dis, -1, (n + 1) * sizeof(int));
dis[s] = 0;
que.push(s);
while(!que.empty())
{
int u = que.front();
que.pop();
for(int i = head[u]; i; i = edge[i].nex)
{
int v = edge[i].to;
if(dis[v] == -1 && edge[i].flow > 0) //可以借助边i到达新的结点
{
dis[v] = dis[u] + 1; //求顶点到源点的距离编号
que.push(v);
}
}
}
return dis[t] != -1; //确认是否连通
}
int dfs(int u, int flow_in)
{
if(u == t) return flow_in;
int flow_out = 0; //记录这一点实际流出的流量
for(int i = cur[u]; i; i = edge[i].nex)
{
cur[u] = i; //由于我们增广的时候都是尽量用尽这条边的容量为前提的,
// 那么在在用尽流入流量之前,我们使用的边,都已经满流了
//没有继续增广的可能了,所以抛弃了这些重复的边,从未满流的边开始遍历
int v = edge[i].to;
if(dis[v] == dis[u] + 1 && edge[i].flow > 0)
{
int flow_part = dfs(v, min(flow_in, edge[i].flow));
if(!flow_part)continue; //无法形成增广路
flow_in -= flow_part; //流出了一部分,剩余可分配流入就减少了
flow_out += flow_part; //记录这一点最大的流出
edge[i].flow -= flow_part;
edge[i ^ 1].flow += flow_part; //减少增广路上边的容量,增加其反向边的容量
if(!flow_in) break;
}
}
return flow_out;
}
int dinic()
{
int maxflow = 0;
while(bfs())
{
for(int i = 0; i <= n ; i ++) cur[i] = head[i];
maxflow += dfs(s, inf);
}
return maxflow;
}
}DI;
signed main()
{
ios;
cin.tie(0) , cout.tie(0);
int n , m , s , t;
cin >> n >> m >> s >> t;
DI.init(n , s , t);
rep(i , 1 , m)
{
int u , v , w;
cin >> u >> v >> w;
DI.add_edge(u , v , w);
}
cout << DI.dinic() << '\n';
return 0;
}