* ---
tags: 高階競技程式設計
---
# Codebook team21_23
## Initial
```C++=
#include<bits/stdc++.h>
#include<numeric>
using namespace std;
int main()
ios::sync_with_stdio(false);
cin.tie(nullptr);
return 0;
}
```
再新增
## Containers
### vector
vector<int> vec(3, 0) - 三個0
vector<T> v(n);
vector<T> v;
vec[i] - 存取索引值為 i 的元素值。
vec.at(i) - 存取索引值為 i 的元素的值,
vec.front() - 回傳 vector 第一個元素的值。
vec.back() - 回傳 vector 最尾元素的值。
vec.push_back(val) - 新增元素至 vector 的尾端,必要時會進行記憶體配置。
vec.pop_back() - 刪除 vector 最尾端的元素。
vec.insert(position,value) - 插入一個或多個元素至 vector 內的任意位置。
vec.erase() - 刪除 vector 中一個或多個元素。
vec.clear() - 清空所有元素。
vec.empty() - 如果 vector 內部為空,則傳回 true 值。
vec.size() - 取得 vector 目前持有的元素個數。
v.resize(n) - 把 vector 的大小調整為 n
v.assign(n, val) - 把 vector 的內容改為 n 個元素,且元素的值為 val
### 其他
WEEK2 課程教材中
## Tool
### string內字母分開存進array
```C++=
char a[];
string str;cin>>str;
int x;x=0;
for(char w:str){
a[x] = w;
x++;
}
```
### 左移陣列
```C++=
rotate(arr.begin(),arr.begin()+d,arr.end())
```
#include <algorithm>
i 選取起始位置 , d 左移次數 , j 選取結束位置
### 右移陣列
```C++=
rotate(arr.begin(),arr.begin()+j-i+1-d ,arr.end())
```
### Array總和
```C++=
accumulate(arr.begin(), arr.end(),0)
```
#include <numeric>
第三項為初始值,一般為0
### Sort
```C++=
bool compare(int a, int b) {
return a > b;
}
sort(arr,arr+x);
sort(arr,arr+x,compare);
//降冪
```
### 多維Sort
```C++=
for(int i=n-1;i>0;i--){
for(int j=0;j<=i-1;j++){
if(a[j][1]>a[j+1][1]){
int t1=a[j][0];
int t2=a[j][1];
a[j][0]=a[j+1][0];
a[j][1]=a[j+1][1];
a[j+1][0]=t1;
a[j+1][1]=t2;
}
}
}
```
視維度增加temp
### Sort 一維陣列(2-block)
```C++=
void sort(int row, int n){
char t1, t2;
for(int j=n-1;j>0;j--){
for(int i=0;i<=j-1;i++){
if(work[row][2*i+2] > work[row][2*i+4]){
t1 = work[row][2*i+1];
t2 = work[row][2*i+2];
work[row][2*i+1] = work[row][2*i+3];
work[row][2*i+2] = work[row][2*i+4];
work[row][2*i+3] = t1;
work[row][2*i+4] = t2;
}
}
}
}
```
### char陣列 轉int
```C++=
for (int i = 0; i < x; i++) {
int ia =(int)a[i];
s[i]=ia-48;
}
```
## Basic
### vimrc
```C++=
=== .vimrc ===
set et nu cin ls=2 ts=4 sw=4 sts=4 ttm=100
syntax on
nn <F4> :w ! cat -n \| lpr <CR>
nn <F7> :w <bar> :!vim %<_.in<left><left><left>
nn <F8> :w <bar> :!g++ % -o %< -std=c++11
\ -fsanitize=undefined -Wall -Wextra -Wshadow -DFOX &&
\ for i in %<_*.in; do echo == && ./%< < $i; done <CR>
nn <F9> :w <bar> :!g++ % -o %< -std=c++11
\ -fsanitize=undefined -Wall -Wextra -Wshadow -DFOX &&
\ echo == && ./%<
```
### default code
```C++=
#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
#include <sys/time.h>
#include <sys/resource.h>
using namespace std;
void setstack(){
// Set soft limit and hard limit to max
const rlimit tmp {RLIM_INFINITY ,RLIM_INFINITY};
setrlimit(RLIMIT_STACK ,&tmp);
}
int main(){
#define name ""
#ifndef FOX
freopen(name".in","r",stdin);
freopen(name".out","w",stdout);
#endif
static_assert(strlen(name));
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
}
```
## Flow
### Dinic
(a) Bounded Maxflow Construction:
1. add two node ss, tt
2. add_edge(ss, tt, INF)
3. for each edge u -> v with capacity [l, r]:
add_edge(u, tt, l)
add_edge(ss, v, l)
add_edge(u, v, r-l)
4. see (b), check if it is possible.
5. answer is maxflow(ss, tt) + maxflow(s, t)
-------------------------------------------------------
(b) Bounded Possible Flow:
1. same construction method as (a)
2. run maxflow(ss, tt)
3. for every edge connected with ss or tt:
rule: check if their rest flow is exactly 0
4. answer is possible if every edge do satisfy the rule
;
5. otherwise, it is NOT possible.
-------------------------------------------------------
(c) Bounded Minimum Flow:
1. same construction method as (a)
2. answer is maxflow(ss, tt)
-------------------------------------------------------
(d) Bounded Minimum Cost Flow:
* the concept is somewhat like bounded possible flow.
1. same construction method as (a)
2. answer is maxflow(ss, tt) + (∑ l * cost for every
edge)
-------------------------------------------------------
(e) Minimum Cut:
1. run maxflow(s, t)
2. run cut(s)
3. ss[i] = 1: node i is at the same side with s.
-------------------------------------------------------
```C++=
const long long INF = 1LL<<60;
struct Dinic { //O(VVE), with minimum cut
static const int MAXN = 5003;
struct Edge{
int u, v;
long long cap, rest;
};
int n, m, s, t, d[MAXN], cur[MAXN];
vector<Edge> edges;
vector<int> G[MAXN];
void init(){
edges.clear();
for ( int i = 0 ; i < n ; i++ ) G[i].clear();
n = 0;
}
// min cut start
bool side[MAXN];
void cut(int u) {
side[u] = 1;
for ( int i : G[u] ) {
if ( !side[ edges[i].v ] && edges[i].rest )
cut(edges[i].v);
}
}
// min cut end
int add_node(){
return n++;
}
void add_edge(int u, int v, long long cap){
edges.push_back( {u, v, cap, cap} );
edges.push_back( {v, u, 0, 0LL} );
m = edges.size();
G[u].push_back(m-2);
G[v].push_back(m-1);
}
bool bfs(){
fill(d,d+n,-1);
queue<int> que;
que.push(s); d[s]=0;
while (!que.empty()){
int u = que.front(); que.pop();
for (int ei : G[u]){
Edge &e = edges[ei];
if (d[e.v] < 0 && e.rest > 0){
d[e.v] = d[u] + 1;
que.push(e.v);
}
}
}
return d[t] >= 0;
}
long long dfs(int u, long long a){
if ( u == t || a == 0 ) return a;
long long flow = 0, f;
for ( int &i=cur[u]; i < (int)G[u].size() ; i++) {
Edge &e = edges[ G[u][i] ];
if ( d[u] + 1 != d[e.v] ) continue;
f = dfs(e.v, min(a, e.rest) );
if ( f > 0 ) {
e.rest -= f;
edges[ G[u][i]^1 ].rest += f;
flow += f;
a -= f;
if ( a == 0 )break;
}
}
return flow;
}
long long maxflow(int _s, int _t){
s = _s, t = _t;
long long flow = 0, mf;
while ( bfs() ){
fill(cur,cur+n,0);
while ( (mf = dfs(s, INF)) ) flow += mf;
}
return flow;
}
} dinic;
```
### GomoryHu tree
-------------------------------------------------------
Construct of Gomory Hu Tree
1. make sure the whole graph is clear
2. set node 0 as root, also be the parent of other nodes.
3. for every node i > 0, we run maxflow from i to parent[i]
4. hense we know the weight between i and parent[i]
5. for each node j > i, if j is at the same side with i , make the parent of j as i
-------------------------------------------------------
```C++=
int e[MAXN][MAXN];
int p[MAXN];
Dinic D; // original graph
void gomory_hu() {
fill(p, p+n, 0);
fill(e[0], e[n], INF);
for ( int s = 1 ; s < n ; s++ ) {
int t = p[s];
Dinic F = D;
int tmp = F.max_flow(s, t);
for ( int i = 1 ; i < s ; i++ )
e[s][i] = e[i][s] = min(tmp, e[t][i]);
for ( int i = s+1 ; i <= n ; i++ )
if ( p[i] == t && F.side[i] ) p[i] = s;
}
}
```
### min cost flow
```C++=
// long long version
typedef pair<long long, long long> pll;
struct CostFlow {
static const int MAXN = 350;
static const long long INF = 1LL<<60;
struct Edge {
int to, r;
long long rest, c;
};
int n, pre[MAXN], preL[MAXN]; bool inq[MAXN];
long long dis[MAXN], fl, cost;
vector<Edge> G[MAXN];
void init() {
for ( int i = 0 ; i < MAXN ; i++) G[i].clear();
}
void add_edge(int u, int v, long long rest, long long c) {
G[u].push_back({v, (int)G[v].size(), rest, c});
G[v].push_back({u, (int)G[u].size()-1, 0, -c});
}
pll flow(int s, int t) {
fl = cost = 0;
while (true) {
fill(dis, dis+MAXN, INF);
fill(inq, inq+MAXN, 0);
dis[s] = 0;
queue<int> que;
que.push(s);
while ( !que.empty() ) {
int u = que.front(); que.pop();
inq[u] = 0;
for ( int i = 0 ; i < (int)G[u].size(); i++) {
int v = G[u][i].to;
long long w = G[u][i].c;
if ( G[u][i].rest > 0 && dis[v] >
dis[u] + w) {
pre[v] = u; preL[v] = i;
dis[v] = dis[u] + w;
if (!inq[v]) {
inq[v] = 1;
que.push(v);
}
}
}
}
if (dis[t] == INF) break;
long long tf = INF;
for (int v = t, u, l ; v != s ; v = u ) {
u = pre[v]; l = preL[v];
tf = min(tf, G[u][l].rest);
}
for (int v = t, u, l ; v != s ; v = u ) {
u = pre[v]; l = preL[v];
G[u][l].rest -= tf;
G[v][G[u][l].r].rest += tf;
}
cost += tf * dis[t];
fl += tf;
}
return {fl, cost};
}
} flow;
```
### SW mincut 全點對最小割
```C++=
// all pair min cut
// global min cut
struct SW{ // O(V^3)
static const int MXN = 514;
int n,vst[MXN],del[MXN];
int edge[MXN][MXN],wei[MXN];
void init(int _n){
n = _n; FZ(edge); FZ(del);
}
void addEdge(int u, int v, int w){
edge[u][v] += w; edge[v][u] += w;
}
void search(int &s, int &t){
FZ(vst); FZ(wei);
s = t = -1;
while (true){
int mx=-1, cur=0;
for (int i=0; i<n; i++)
if (!del[i] && !vst[i] && mx<wei[i])
cur = i, mx = wei[i];
if (mx == -1) break;
vst[cur] = 1;
s = t; t = cur;
for (int i=0; i<n; i++)
if (!vst[i] && !del[i]) wei[i] += edge[cur][i];
}
}
int solve(){
int res = 2147483647;
for (int i=0,x,y; i<n-1; i++){
search(x,y);
res = min(res,wei[y]);
del[y] = 1;
for (int j=0; j<n; j++)
edge[x][j] = (edge[j][x] += edge[y][j]);
}
return res;
}
}graph;
```
## Matching
### Hungarian
```C++=
// Maximum Cardinality Bipartite Matching
// Worst case O(nm)
struct Graph{
static const int MAXN = 5003;
vector<int> G[MAXN];
int n, match[MAXN], vis[MAXN];
void init(int _n){
n = _n;
for (int i=0; i<n; i++) G[i].clear();
}
bool dfs(int u){
for (int v:G[u]){
if (vis[v]) continue;
vis[v]=true;
if (match[v]==-1 || dfs(match[v])){
match[v] = u;
match[u] = v;
return true;
}
}
return false;
}
int solve(){
int res = 0;
memset(match,-1,sizeof(match));
for (int i=0; i<n; i++){
if (match[i]==-1){
memset(vis,0,sizeof(vis));
if ( dfs(i) ) res++;
}
}
return res;
}
} graph;
```
### KM
```C++=
const int MAXN = 400 + 10;
const long long INF64 = 0x3f3f3f3f3f3f3f3fll;
int nl, nr;
int pre[MAXN];
long long slack[MAXN];
long long W[MAXN][MAXN];
long long lx[MAXN], ly[MAXN];
int mx[MAXN], my[MAXN];
bool vx[MAXN], vy[MAXN];
void augment(int u) {
if(!u) return;
augment(mx[pre[u]]);
mx[pre[u]] = u;
my[u] = pre[u];
}
void match(int x) {
queue<int> que;
que.push(x);
while(1) {
while(!que.empty()) {
x = que.front(); que.pop();
vx[x] = 1;
for (int i=1; i<=nr; i++) {
if(vy[i]) continue;
long long t = lx[x] + ly[i] - W[x][i];
if(t > 0) {
if(slack[i] >= t) slack[i] = t, pre
[i] = x;
continue;
}
pre[i] = x;
if(!my[i]) {
augment(i);
return;
}
vy[i] = 1;
que.push(my[i]);
}
}
long long t = INF64;
for (int i=1; i<=nr; i++) if(!vy[i]) t = min(t,slack[i]);
for (int i=1; i<=nl; i++) if(vx[i]) lx[i] -= t;
for (int i=1; i<=nr; i++) {
if(vy[i]) ly[i] += t;
else slack[i] -= t;
}
for (int i=1; i<=nr; i++) {
if(vy[i] || slack[i]) continue;
if(!my[i]) {
augment(i);
return;
}
vy[i] = 1;
que.push(my[i]);
}
}
}
int main() {
int m;
cin >> nl >> nr >> m;
nr = max(nl, nr);
while(m--) {
int u, v;
long long w;
cin >> u >> v >> w;
W[u][v] = w;
lx[u] = max(lx[u], w);
}
for (int i=1; i<=nl; i++) {
for (int x=1; x<=nl; x++) vx[x] = 0;
for (int y=1; y<=nr; y++) vy[y] = 0, slack[y] = INF64; match(i);
}
long long ans = 0;
for (int i=1; i<=nl; i++) ans += W[i][mx[i]];
cout << ans << '\n';
for (int i=1; i<=nl; i++) {
if (i > 1) cout << ' ';
cout << (W[i][mx[i]] ? mx[i] : 0);
}
cout << '\n';
}
```
### Matching.txt
最 大 匹 配 + 最 小 邊 覆 蓋 = V
最 大 獨 立 集 + 最 小 點 覆 蓋 = V
最 大 匹 配 = 最 小 點 覆 蓋
最 小 路 徑 覆 蓋 數 = V - 最 大 匹 配 數
### Maximum General Matching
```C++=
// Maximum Cardinality Matching
struct Graph {
vector<int> G[MAXN];
int pa[MAXN], match[MAXN], st[MAXN], S[MAXN], vis[
MAXN];
int t, n;
void init(int _n) {
n = _n;
for ( int i = 1 ; i <= n ; i++ ) G[i].clear();
}
void add_edge(int u, int v) {
G[u].push_back(v);
G[v].push_back(u);
}
int lca(int u, int v){
for ( ++t ; ; swap(u, v) ) {
if ( u == 0 ) continue;
if ( vis[u] == t ) return u;
vis[u] = t;
u = st[ pa[ match[u] ] ];
}
}
void flower(int u, int v, int l, queue<int> &q) {
while ( st[u] != l ) {
pa[u] = v;
if ( S[ v = match[u] ] == 1 ) {
q.push(v);
S[v] = 0;
}
st[u] = st[v] = l;
u = pa[v];
}
}
bool bfs(int u){
for ( int i = 1 ; i <= n ; i++ ) st[i] = i;
memset(S, -1, sizeof(S));
queue<int>q;
q.push(u);
S[u] = 0;
while ( !q.empty() ) {
u = q.front(); q.pop();
for ( int i = 0 ; i < (int)G[u].size(); i++) {
int v = G[u][i];
if ( S[v] == -1 ) {
pa[v] = u;
S[v] = 1;
if ( !match[v] ) {
for ( int lst ; u ; v = lst, u = pa[v] ) {
lst = match[u];
match[u] = v;
match[v] = u;
}
return 1;
}
q.push(match[v]);
S[ match[v] ] = 0;
} else if ( !S[v] && st[v] != st[u] ) {
int l = lca(st[v], st[u]);
flower(v, u, l, q);
flower(u, v, l, q);
}
}
}
return 0;
}
int solve(){
memset(pa, 0, sizeof(pa));
memset(match, 0, sizeof(match));
int ans = 0;
for ( int i = 1 ; i <= n ; i++ )
if ( !match[i] && bfs(i) ) ans++;
return ans;
}
} graph;
```
### Minimum General Weighted Matching
```C++=
// Minimum Weight Perfect Matching (Perfect Match)
struct Graph {
static const int MAXN = 105;
int n, e[MAXN][MAXN];
int match[MAXN], d[MAXN], onstk[MAXN];
vector<int> stk;
void init(int _n) {
n = _n;
for( int i = 0 ; i < n ; i ++ )
for( int j = 0 ; j < n ; j ++ )
e[i][j] = 0;
}
void add_edge(int u, int v, int w) {
e[u][v] = e[v][u] = w;
}
bool SPFA(int u){
if (onstk[u]) return true;
stk.push_back(u);
onstk[u] = 1;
for ( int v = 0 ; v < n ; v++ ) {
if (u != v && match[u] != v && !onstk[v] )
{
int m = match[v];
if ( d[m] > d[u] - e[v][m] + e[u][v] )
{
d[m] = d[u] - e[v][m] + e[u][v];
onstk[v] = 1;
stk.push_back(v);
if (SPFA(m)) return true;
stk.pop_back();
onstk[v] = 0;
}
}
}
onstk[u] = 0;
stk.pop_back();
return false;
}
int solve() {
for ( int i = 0 ; i < n ; i += 2 ) {
match[i] = i+1;
match[i+1] = i;
}
while (true){
int found = 0;
for ( int i = 0 ; i < n ; i++ )
onstk[ i ] = d[ i ] = 0;
for ( int i = 0 ; i < n ; i++ ) {
stk.clear();
if ( !onstk[i] && SPFA(i) ) {
found = 1;
while ( stk.size() >= 2 ) {
int u = stk.back(); stk.
pop_back();
int v = stk.back(); stk.
pop_back();
match[u] = v;
match[v] = u;
}
}
}
if (!found) break;
}
int ret = 0;
for ( int i = 0 ; i < n ; i++ )
ret += e[i][match[i]];
ret /= 2;
return ret;
}
} graph;
```
## Graph
• Maximum Independent Set
– General: [NPC] maximum clique of complement of G
– Bipartite Graph: [P] Maximum Cardinality Bipartite Matching
– Tree: [P] dp
• Minimum Dominating Set
– General: [NPC]
– Bipartite Graph: [NPC]
– Tree: [P] DP
• Minimum Vertex Cover
– General: [NPC] (?)maximum clique of complement of G
– Bipartite Graph: [P] Maximum Cardinality Bipartite Matching
– Tree: [P] Greedy, from leaf to root
• Minimum Edge Cover
– General: [P] V - Maximum Matching
– Bipartite Graph: [P] Greedy, strategy: cover small degree node first.
– (Min/Max)Weighted: [P]: Minimum/Minimum Weight Matching
### BCC edge
邊 雙 連 通
任 意 兩 點 間 至 少 有 兩 條 不 重 疊 的 路 徑 連 接, 找 法:
1. 標 記 出 所 有 的 橋
2. 對 全 圖 進 行 DFS, 不 走 橋, 每 一 次 DFS 就 是 一 個 新 的 邊 雙 連 通
```C++=
// from BCW
struct BccEdge {
static const int MXN = 100005;
struct Edge { int v,eid; };
int n,m,step,par[MXN],dfn[MXN],low[MXN];
vector<Edge> E[MXN];
DisjointSet djs;
void init(int _n) {
n = _n; m = 0;
for (int i=0; i<n; i++) E[i].clear();
djs.init(n);
}
void add_edge(int u, int v) {
E[u].PB({v, m});
E[v].PB({u, m});
m++;
}
void DFS(int u, int f, int f_eid) {
par[u] = f;
dfn[u] = low[u] = step++;
for (auto it:E[u]) {
if (it.eid == f_eid) continue;
int v = it.v;
if (dfn[v] == -1) {
DFS(v, u, it.eid);
low[u] = min(low[u], low[v]);
} else {
low[u] = min(low[u], dfn[v]);
}
}
}
void solve() {
step = 0;
memset(dfn, -1, sizeof(int)*n);
for (int i=0; i<n; i++) {
if (dfn[i] == -1) DFS(i, i, -1);
}
djs.init(n);
for (int i=0; i<n; i++) {
if (low[i] < dfn[i]) djs.uni(i, par[i]);
}
}
}graph;
```
### Dijkstra
```C++=
struct Edge{
int v; long long len;
bool operator < (const Edge &b)const { return len>b
.len; }
};
const long long INF = 1LL<<60;
void Dijkstra(int n, vector<Edge> G[], long long d[],
int s, int t=-1){
static priority_queue <Edge> pq;
while ( pq.size() )pq.pop();
for (int i=1; i<=n; i++)d[i]=INF;
d[s]=0; pq.push( {s,d[s]} );
while ( pq.size() ){
auto x = pq.top(); pq.pop();
int u = x.v;
if (d[u]<x.len)continue;
if (u==t)return;
for (auto &e:G[u]){
if (d[e.v] > d[u]+e.len){
d[e.v] = d[u]+e.len;
pq.push( {e.v,d[e.v]} );
}
}
}
}
```
### Domination.txt
#### Maximum Independent Set
General: [NPC] maximum clique of complement of G
Tree: [P] Greedy
Bipartite Graph: [P] Maximum Cardinality Bipartite Matching
#### Minimum Dominating Set
General: [NPC]
Tree: [P] DP
Bipartite Graph: [NPC]
#### Minimum Vertex Cover
General: [NPC] (?)maximum clique of complement of G
Tree: [P] Greedy, from leaf to root
Bipartite Graph: [P] Maximum Cardinality Bipartite Matching
#### Minimum Edge Cover
General: [P] V - Maximum Matching
Bipartite Graph: [P] Greedy, strategy: cover small degree node first.
(Min/Max)Weighted: [P]: Minimum/Minimum Weight Matching
### max clique
```C++=
const int MAXN = 105;
int best;
int n;
int num[MAXN];
int path[MAXN];
int G[MAXN][MAXN];
bool dfs( int *adj, int total, int cnt ){
int t[MAXN];
if (total == 0){
if( best < cnt ){
best = cnt;
return true;
}
return false;
}
for(int i = 0; i < total; i++){
if( cnt+(total-i) <= best ) return false;
if( cnt+num[adj[i]] <= best ) return false;
int k=0;
for(int j=i+1; j<total; j++)
if(G[ adj[i] ][ adj[j] ])
t[k++] = adj[j];
if (dfs(t, k, cnt+1)) return true;
}
return false;
}
int MaximumClique(){
int adj[MAXN];
if (n <= 0) return 0;
best = 0;
for(int i = n-1; i >= 0; i--){
int k=0;
for(int j = i+1; j < n; j++)
if (g[i][j]) adj[k++] = j;
dfs( adj, k, 1 );
num[i] = best;
}
return best;
}
```
### min mean cycle
```C++=
// from BCW
/* minimum mean cycle */
const int MAXE = 1805;
const int MAXN = 35;
const double inf = 1029384756;
const double eps = 1e-6;
struct Edge {
int v,u;
double c;
};
int n,m,prv[MAXN][MAXN], prve[MAXN][MAXN], vst[MAXN];
Edge e[MAXE];
vector<int> edgeID, cycle, rho;
double d[MAXN][MAXN];
inline void bellman_ford() {
for(int i=0; i<n; i++) d[0][i]=0;
for(int i=0; i<n; i++) {
fill(d[i+1], d[i+1]+n, inf);
for(int j=0; j<m; j++) {
int v = e[j].v, u = e[j].u;
if(d[i][v]<inf && d[i+1][u]>d[i][v]+e[j].c) {
d[i+1][u] = d[i][v]+e[j].c;
prv[i+1][u] = v;
prve[i+1][u] = j;
}
}
}
}
double karp_mmc() {
// returns inf if no cycle, mmc otherwise
double mmc=inf;
int st = -1;
bellman_ford();
for(int i=0; i<n; i++) {
double avg=-inf;
for(int k=0; k<n; k++) {
if(d[n][i]<inf-eps) avg=max(avg,(d[n][i]-d[k][i])
/(n-k));
else avg=max(avg,inf);
}
if (avg < mmc) tie(mmc, st) = tie(avg, i);
}
for(int i=0; i<n; i++) vst[i] = 0;
edgeID.clear(); cycle.clear(); rho.clear();
for (int i=n; !vst[st]; st=prv[i--][st]) {
vst[st]++;
edgeID.PB(prve[i][st]);
rho.PB(st);
}
while (vst[st] != 2) {
int v = rho.back(); rho.pop_back();
cycle.PB(v);
vst[v]++;
}
reverse(ALL(edgeID));
edgeID.resize(SZ(cycle));
return mmc;
}
```
### SSSP related concepts
最 短 路 問 題 分 類:
三 個 工 具 Bellman-Ford, Floyd, Dijkstra,
1. 可 以 把 Dijkstra Priority Queue 裡 面 存 的 東 西 想 成 「狀 態」, 他 可 以 拿 來 統 計 甚 至 轉 移。
2. 當 遇 到 邊 權 會 扣 掉 走 的 人 的 血 量 (或 油 量 之 類 的), 當 不 能 有 負 值 的 時 候, 就 要 使 用 Bellman-Ford 來 做, 一 開 始 可 以 把 起 點 設 為 最 初 的 血 量 (油 量), 拿 去 做 BellmanFord, 當 做 了 n-1 次 之 後, 還 能 轉 移, 那 就 是 有 負 環 或 正 環 (端 看 如 何 轉 移 Bellman-Ford, 這 部 分 的 轉 移 式 很 自 由 可 以 依 照 題 目 敘 述 亂 改。)
3. 特 別 注 意 如 果 要 判 到 某 一 個 點 的 ⻑ 度 是 不 是 無 限 小, 可 在 做 了 n-1 次 之 後, 發 現 u->v 可 以 更 新, 那 我 可 以 去 看 v 是 否 可 以 到 另 一 點 k, 如 果 是 聯 通 的, 代 表 k 這 個 點 的 ⻑ 度 是 無 限 小。
### Tarjan.cpp
#### 割 點
點 u 為 割 點 if and only if 滿 足 1. or 2.
1. u 爲 樹 根, 且 u 有 多 於 一 個 子 樹。
2. u 不 爲 樹 根, 且 滿 足 存 在 (u,v) 爲 樹 枝 邊 (或 稱 父 子 邊, 即 u 爲 v 在 搜 索 樹 中 的 父 親), 使 得 DFN(u) <= Low(v) 。
-------------------------------------------------------
#### 橋
一 條 無 向 邊 (u,v) 是 橋 if and only if (u,v) 爲 樹 枝 邊, 且 滿 足 DFN(u) < Low(v)。
```C++=
// 0 base
struct TarjanSCC{
static const int MAXN = 1000006;
int n, dfn[MAXN], low[MAXN], scc[MAXN], scn, count;
vector<int> G[MAXN];
stack<int> stk;
bool ins[MAXN];
void tarjan(int u){
dfn[u] = low[u] = ++count;
stk.push(u);
ins[u] = true;
for(auto v:G[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(dfn[u] == low[u]){
int v;
do {
v = stk.top();
stk.pop();
scc[v] = scn;
ins[v] = false;
} while(v != u);
scn++;
}
}
void getSCC(){
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(ins,0,sizeof(ins));
memset(scc,0,sizeof(scc));
count = scn = 0;
for(int i = 0 ; i < n ; i++ ){
if(!dfn[i]) tarjan(i);
}
}
}SCC;
```
### 2-SAT
```C++=
const int MAXN = 2020;
struct TwoSAT{
static const int MAXv = 2*MAXN;
vector<int> GO[MAXv],BK[MAXv],stk;
bool vis[MAXv];
int SC[MAXv];
void imply(int u,int v){ // u imply v
GO[u].push_back(v);
BK[v].push_back(u);
}
int dfs(int u,vector<int>*G,int sc){
vis[u]=1, SC[u]=sc;
for (int v:G[u])if (!vis[v])
dfs(v,G,sc);
if (G==GO)stk.push_back(u);
}
int scc(int n=MAXv){
memset(vis,0,sizeof(vis));
for (int i=0; i<n; i++)if (!vis[i])
dfs(i,GO,-1);
memset(vis,0,sizeof(vis));
int sc=0;
while (!stk.empty()){
if (!vis[stk.back()])
dfs(stk.back(),BK,sc++);
stk.pop_back();
}
}
}SAT;
int main(){
SAT.scc(2*n);
bool ok=1;
for (int i=0; i<n; i++){
if (SAT.SC[2*i]==SAT.SC[2*i+1])ok=0;
}
if (ok){
for (int i=0; i<n; i++){
if (SAT.SC[2*i]>SAT.SC[2*i+1]){
cout << i << endl;
}
}
}
else puts("NO");
}
void warshall(){
bitset <2003> d[2003];
for (int k=0; k<n; k++){
for (int i=0; i<n; i++) if (d[i][k]) {
d[i] |= d[k];
}
}
}
```
### 平面圖判定
```C++=
//skydog
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <iomanip>
#include <vector>
#include <cstring>
#include <string>
#include <queue>
#include <deque>
#include <stack>
#include <map>
#include <set>
#include <utility>
#include <list>
#include <cmath>
#include <algorithm>
#include <cassert>
#include <bitset>
#include <complex>
#include <climits>
#include <functional>
using namespace std;
typedef long long ll;
typedef pair<int, int> ii;
typedef pair<ll, ll> l4;
#define mp make_pair
#define pb push_back
#define debug(x) cerr << #x << " = " << x << " "
const int N=400+1;
struct Planar
{
int n,m,hash[N],fa[N],deep[N],low[N],ecp[N];
vector<int> g[N],son[N];
set< pair<int,int> > SDlist[N],proots[N];
int nxt[N][2],back[N],rev[N];
deque<int> q;
void dfs(int u)
{
hash[u]=1; q.pb(u);
ecp[u]=low[u]=deep[u];
int v;
for (int i = 0; i < g[u].size(); ++i)
if(!hash[v=g[u][i]])
{
fa[v]=u;
deep[v]=deep[u]+1;
dfs(v);
low[u]=min(low[u],low[v]);
SDlist[u].insert(mp(low[v],v));
}
else ecp[u]=min(ecp[u],deep[v]);
low[u]=min(low[u],ecp[u]);
}
int visited[N];
void addtree(int u,int t1,int v,int t2)
{
nxt[u][t1]=v; nxt[v][t2]=u;
}
void findnxt(int u,int v,int& u1,int& v1)
{
u1=nxt[u][v^1];
if(nxt[u1][0]==u) v1=0;
else v1=1;
}
void walkup(int u,int v)
{
back[v]=u;
int v1=v,v2=v,u1=1,u2=0,z;
for (;;)
{
if(hash[v1]==u || hash[v2]==u) break;
hash[v1]=u;hash[v2]=u; z=max(v1,v2);
if(z>n)
{
int p=fa[z-n];
if(p!=u)
{
proots[p].insert(mp(-low[z-n], z));
v1=p,v2=p,u1=0,u2=1;
}
else break;
}
else
{
findnxt(v1,u1,v1,u1);
findnxt(v2,u2,v2,u2);
}
}
}
int topstack;
pair<int,int> stack[N];
int outer(int u,int v)
{
return ecp[v]<deep[u] || (SDlist[v].size() &&
SDlist[v].begin()->first<deep[u]);
}
int inside(int u,int v)
{
return proots[v].size()>0 || back[v]==u;
}
int active(int u,int v)
{
return inside(u,v) || outer(u,v);
}
void push(int a,int b)
{
stack[++topstack]=mp(a,b);
}
void mergestack()
{
int v1,t1,v2,t2,s,s1;
v1=stack[topstack].first;t1=stack[topstack].
second;
topstack --;
v2=stack[topstack].first;t2=stack[topstack].
second;
topstack --;
s=nxt[v1][t1^1];
s1=(nxt[s][1]==v1);
nxt[s][s1]=v2;
nxt[v2][t2]=s;
SDlist[v2].erase( make_pair(low[v1-n],v1-n) );
proots[v2].erase( make_pair(-low[v1-n],v1) );
}
void findnxtActive(int u,int t,int& v,int& w1,int S
)
{
findnxt(u,t,v,w1);
while(u!=v && !active(S,v))
findnxt(v,w1,v,w1);
}
void walkdown(int S,int u)
{
topstack=0;
int t1,v=S,w1,x2,y2,x1,y1,p;
for(t1=0;t1<2;++t1)
{
findnxt(S,t1^1,v,w1);
while(v!=S)
{
if(back[v]==u)
{
while(topstack >0) mergestack();
addtree(S,t1,v,w1); back[v]=0;
}
if(proots[v].size())
{
push(v,w1);
p=proots[v].begin()->second;
findnxtActive(p,1,x1,y1,u);
findnxtActive(p,0,x2,y2,u);
if(active(u,x1) && !outer(u,x1))
v=x1,w1=y1;
else if(active(u,x2) && !outer(u,x2
))
v=x2,w1=y2;
else if(inside(u,x1) || back[x1]==u
)
v=x1,w1=y1;
else v=x2,w1=y2;
push(p,v==x2);
}
else if(v>n || ( ecp[v]>=deep[u] && !
outer(u,v) ))
findnxt(v,w1,v,w1);
else if(v<=n && outer(u,v) && !topstack
)
{
addtree(S,t1,v,w1); break;
}
else break;
}
}
}
int work(int u)
{
int v;
for (int i = 0; i < g[u].size(); ++i)
if(fa[v=g[u][i]]==u)
{
son[u].push_back(n+v);
proots[n+v].clear();
addtree(n+v,1,v,0);
addtree(n+v,0,v,1);
}
for (int i = 0; i < g[u].size(); ++i)
if(deep[v=g[u][i]]>deep[u]+1)
walkup(u,v);
topstack=0;
for (int i = 0; i < son[u].size(); ++i)
walkdown(son[u][i], u);
for (int i = 0; i < g[u].size(); ++i)
if(deep[v=g[u][i]]>deep[u]+1 && back[v])
return 0;
return 1;
}
void init(int _n)
{
n = _n;
m = 0;
for(int i=1;i<=2*n;++i)
{
g[i].clear();
SDlist[i].clear();
son[i].clear();
proots[i].clear();
nxt[i][0]=nxt[i][1]=0;
fa[i]=0;
hash[i]=0;low[i]=ecp[i]=deep[i]=back[i]=0;
q.clear();
}
}
void add(int u, int v)
{
++m;
g[u].pb(v); g[v].pb(u);
}
bool check_planar()
{
if(m>3*n-5)
return false;
// memset(hash,0,sizeof hash);
for(int i=1;i<=n;++i)
if(!hash[i])
{
deep[i]=1;
dfs(i);
}
memset(hash,0,sizeof hash);
//memset(hash, 0, (2*n+1)*sizeof(hash[0]));
// originally only looks at last n element
assert(q.size() == n);
while (!q.empty())
{
if (!work(q.back()))
return false;
q.pop_back();
}
return true;
}
} base, _new;
vector<ii> edges;
int n, m;
inline void build(int n, Planar &_new)
{
_new.init(n);
for (auto e : edges)
_new.add(e.first, e.second);
}
void end()
{
puts("-1");
exit(0);
}
bool vis[N];
const int maxp = 5;
int path[maxp], tp=0;
void dfs(int cur)
{
vis[cur] = true;
path[tp++] = cur;
if (tp == maxp)
{
auto it = lower_bound(base.g[cur].begin(), base.g[
cur].end(), path[0]);
if ( it != base.g[cur].end() && *it == path[0])
{
//a cycle
int x = n+1;
for (int i = 0; i < 5; ++i) edges.pb(mp(x,
path[i]));
build(x, _new);
if (_new.check_planar())
{
for (int i = 0; i < maxp; ++i) printf("
%d%c", path[i], i==maxp-1?'\n':' ')
;
exit(0);
}
for (int i = 0; i < 5; ++i) edges.pop_back
();
}
}
else
{
for (auto e : base.g[cur]) if (!vis[e]) dfs(e);
}
vis[cur] = false;
--tp;
}
int main()
{
scanf("%d %d", &n, &m);
if (n <= 4)
{
assert(false);
puts("0"); return 0;
}
for (int i = 0; i < m; ++i)
{
int u, v; scanf("%d %d", &u, &v);
edges.pb(mp(u, v));
}
build(n, base);
if (!base.check_planar()) end();
for (int i = 1; i <= n; ++i)
sort(base.g[i].begin(), base.g[i].end());
for (int i = 1; i <= n; ++i)
dfs(i);
end();
}
```
## Math
待新增
### ax+by=gcd(a,b)
```C++=
pair<int,int> extgcd(int a, int b){
if (b==0) return {1,0};
int k = a/b;
pair<int,int> p = extgcd(b,a-k*b);
return { p.second, p.first - k*p.second };
}
```
### FFT
```C++=
// use llround() to avoid EPS
typedef double Double;
const Double PI = acos(-1);
// STL complex may TLE
typedef complex<Double> Complex;
#define x real()
#define y imag()
template<typename Iter> // Complex*
void BitReverse(Iter a, int n){
for (int i=1, j=0; i<n; i++){
for (int k = n>>1; k>(j^=k); k>>=1);
if (i<j) swap(a[i],a[j]);
}
}
template<typename Iter> // Complex*
void FFT(Iter a, int n, int rev=1){ // rev = 1 or -1
assert( (n&(-n)) == n ); // n is power of 2
BitReverse(a,n);
Iter A = a;
for (int s=1; (1<<s)<=n; s++){
int m = (1<<s);
Complex wm( cos(2*PI*rev/m), sin(2*PI*rev/m) );
for (int k=0; k<n; k+=m){
Complex w(1,0);
for (int j=0; j<(m>>1); j++){
Complex t = w * A[k+j+(m>>1)];
Complex u = A[k+j];
A[k+j] = u+t;
A[k+j+(m>>1)] = u-t;
w = w*wm;
}
}
}
if (rev==-1){
for (int i=0; i<n; i++){
A[i] /= n;
}
}
}
```
### NTT
```C++=
// Remember coefficient are mod P
// {n, 2^n, p, a, root} Note: p = a*2^n+1
// {16, 65536, 65537, 1, 3}
// {20, 1048576, 7340033, 7, 3}
template < LL P, LL root, int MAXN > // (must be 2^k)
struct NTT {
static LL bigmod(LL a, LL b) {
LL res = 1;
for (LL bs = a; b; b >>= 1, bs = (bs * bs) % P)
if (b & 1) res = (res * bs) % P;
return res;
}
static LL inv(LL a, LL b) {
if (a == 1) return 1;
return (((LL)(a - inv(b % a, a)) * b + 1) / a)
% b;
}
LL omega[MAXN + 1];
NTT() {
omega[0] = 1;
LL r = bigmod(root, (P - 1) / MAXN);
for (int i = 1; i <= MAXN; i++)
omega[i] = (omega[i - 1] * r) % P;
}
// n must be 2^k
void tran(int n, LL a[], bool inv_ntt = false) {
int basic = MAXN / n, theta = basic;
for (int m = n; m >= 2; m >>= 1) {
int mh = m >> 1;
for (int i = 0; i < mh; i++) {
LL w = omega[i * theta % MAXN];
for (int j = i; j < n; j += m) {
int k = j + mh;
LL x = a[j] - a[k];
if (x < 0) x += P;
a[j] += a[k];
if (a[j] > P) a[j] -= P;
a[k] = (w * x) % P;
}
}
theta = (theta * 2) % MAXN;
}
int i = 0;
for (int j = 1; j < n - 1; j++) {
for (int k = n >> 1; k > (i ^= k); k >>= 1)
;
if (j < i) swap(a[i], a[j]);
}
if (inv_ntt) {
LL ni = inv(n, P);
reverse(a + 1, a + n);
for (i = 0; i < n; i++)
a[i] = (a[i] * ni) % P;
}
}
};
const LL P=2013265921, root=31;
const int MAXN=4194304; // MAXN 的 因 數 也 可 以 跑
NTT<P, root, MAXN> ntt;
```
### GaussElimination
```C++=
// by bcw_codebook
const int MAXN = 300;
const double EPS = 1e-8;
int n;
double A[MAXN][MAXN];
void Gauss() {
for(int i = 0; i < n; i++) {
bool ok = 0;
for(int j = i; j < n; j++) {
if(fabs(A[j][i]) > EPS) {
swap(A[j], A[i]);
ok = 1;
break;
}
}
if(!ok) continue;
double fs = A[i][i];
for(int j = i+1; j < n; j++) {
double r = A[j][i] / fs;
for(int k = i; k < n; k++) {
A[j][k] -= A[i][k] * r;
}
}
}
}
```
### inverse
```C++=
const int MAXN = 1000006;
int inv[MAXN];
void invTable(int bound, int p){
inv[1] = 1;
for (int i=2; i<bound; i++){
inv[i] = (long long)inv[p%i] * (p-p/i) %p;
}
}
int inv(int b, int p){
if (b==1) return 1;
return (long long)inv(p%b,p) * (p-p/b) %p;
}
```
### Miller-Rabin
```C++=
typedef long long LL;
inline LL bin_mul(LL a, LL n,const LL& MOD){
LL re=0;
while (n>0){
if (n&1) re += a;
a += a; if (a>=MOD) a-=MOD;
n>>=1;
}
return re%MOD;
}
inline LL bin_pow(LL a, LL n,const LL& MOD){
LL re=1;
while (n>0){
if (n&1) re = bin_mul(re,a,MOD);
a = bin_mul(a,a,MOD);
n>>=1;
}
return re;
}
bool is_prime(LL n){
//static LL sprp[3] = { 2LL, 7LL, 61LL};
static LL sprp[7] = { 2LL, 325LL, 9375LL,
28178LL, 450775LL, 9780504LL,
1795265022LL };
if (n==1 || (n&1)==0 ) return n==2;
int u=n-1, t=0;
while ( (u&1)==0 ) u>>=1, t++;
for (int i=0; i<3; i++){
LL x = bin_pow( sprp[i]%n, u, n);
if (x==0 || x==1 || x==n-1)continue;
for (int j=1; j<t; j++){
x=x*x%n;
if (x==1 || x==n-1)break;
}
if (x==n-1)continue;
return 0;
}
return 1;
}
```
### Mobius
```C++=
void mobius() {
fill(isPrime, isPrime + MAXN, 1);
mu[1] = 1, num = 0;
for (int i = 2; i < MAXN; ++i) {
if (isPrime[i]) primes[num++] = i, mu[i] = -1;
static int d;
for (int j = 0; j < num && (d = i * primes[j])
< MAXN; ++j) {
isPrime[d] = false;
if (i % primes[j] == 0) {
mu[d] = 0; break;
} else mu[d] = -mu[i];
}
}
}
```
### pollardRho
```C++=
// from PEC
// does not work when n is prime
Int f(Int x, Int mod){
return add(mul(x, x, mod), 1, mod);
}
Int pollard_rho(Int n) {
if ( !(n & 1) ) return 2;
while (true) {
Int y = 2, x = rand()%(n-1) + 1, res = 1;
for ( int sz = 2 ; res == 1 ; sz *= 2 ) {
for ( int i = 0 ; i < sz && res <= 1 ; i++) {
x = f(x, n);
res = __gcd(abs(x-y), n);
}
y = x;
}
if ( res != 0 && res != n ) return res;
}
}
```
### SG
#### Anti Nim (取 走 最 後 一 個 石 子 者 敗)
先 手 必 勝 if and only if
1. 「所 有」 堆 的 石 子 數 都 為 1 且 遊 戲 的 SG 值 為 0。
2. 「有 些」 堆 的 石 子 數 大 於 1 且 遊 戲 的 SG 值 不 為 0。
-------------------------------------------------------
#### Anti-SG (決 策 集 合 為 空 的 遊 戲 者 贏)
定 義 SG 值 為 0 時, 遊 戲 結 束,
則 先 手 必 勝 if and only if
1. 遊 戲 中 沒 有 單 一 遊 戲 的 SG 函 數 大 於 1 且 遊 戲 的 SG 函 數 為 0。
2. 遊 戲 中 某 個 單 一 遊 戲 的 SG 函 數 大 於 1 且 遊 戲 的 SG 函 數 不 為 0。
-------------------------------------------------------
#### Sprague-Grundy
1. 雙 人、 回 合 制
2. 資 訊 完 全 公 開
3. 無 隨 機 因 素
4. 可 在 有 限 步 內 結 束
5. 沒 有 和 局
6. 雙 方 可 採 取 的 行 動 相 同
SG(S) 的 值 為 0: 後 手(P)必 勝
不 為 0: 先 手(N)必 勝
```C++=
int mex(set S) {
// find the min number >= 0 that not in the S
// e.g. S = {0, 1, 3, 4} mex(S) = 2
}
state = []
int SG(A) {
if (A not in state) {
S = sub_states(A)
if( len(S) > 1 ) state[A] = reduce(operator.xor, [
SG(B) for B in S])
else state[A] = mex(set(SG(B) for B in next_states(
A)))
}
return state[A]
}
```
### theorem
```C++=
/*
Lucas's Theorem
For non-negative integer n,m and prime P,
C(m,n) mod P = C(m/M,n/M) * C(m%M,n%M) mod P
= mult_i ( C(m_i,n_i) )
where m_i is the i-th digit of m in base P.
-------------------------------------------------------
Kirchhoff's theorem
A_{ii} = deg(i), A_{ij} = (i,j) \in E ? -1 : 0
Deleting any one row, one column, and cal the det(A)
-------------------------------------------------------
Nth Catalan recursive function:
C_0 = 1, C_{n+1} = C_n * 2(2n + 1)/(n+2)
-------------------------------------------------------
Mobius Formula
u(n) = 1 , if n = 1
(-1)^m , 若 n 無 平 方 數 因 數, 且 n = p1*p2*p3
*...*pk
0 , 若 n 有 大 於 1 的 平 方 數 因 數
- Property
1. (積 性 函 數) u(a)u(b) = u(ab)
2. ∑_{d|n} u(d) = [n == 1]
-------------------------------------------------------
Mobius Inversion Formula
if f(n) = ∑_{d|n} g(d)
then g(n) = ∑_{d|n} u(n/d)f(d)
= ∑_{d|n} u(d)f(n/d)
- Application
the number/power of gcd(i, j) = k
- Trick
分 塊, O(sqrt(n))
-------------------------------------------------------
Chinese Remainder Theorem (m_i 兩 兩 互 質)
x = a_1 (mod m_1)
x = a_2 (mod m_2)
....
x = a_i (mod m_i)
construct a solution:
Let M = m_1 * m_2 * m_3 * ... * m_n
Let M_i = M / m_i
t_i = 1 / M_i
t_i * M_i = 1 (mod m_i)
solution x = a_1 * t_1 * M_1 + a_2 * t_2 * M_2 + ...
+ a_n * t_n * M_n + k * M
= k*M + ∑ a_i * t_i * M_i, k is positive integer.
under mod M, there is one solution x = ∑ a_i * t_i *
M_i
-------------------------------------------------------
Burnside's lemma
|G| * |X/G| = sum( |X^g| ) where g in G
總 方 法 數: 每 一 種 旋 轉 下 不 動 點 的 個 數 總 和 除 以 旋 轉 的 方 法
數
*/
```
## Geometry
### 2D point template
```C++=
typedef double Double;
struct Point {
Double x,y;
bool operator < (const Point &b)const{
//return tie(x,y) < tie(b.x,b.y);
//return atan2(y,x) < atan2(b.y,b.x);
assert(0 && "choose compare");
}
Point operator + (const Point &b)const{
return {x+b.x,y+b.y};
}
Point operator - (const Point &b)const{
return {x-b.x,y-b.y};
}
Point operator * (const Double &d)const{
return {d*x,d*y};
}
Point operator / (const Double &d)const{
return {x/d,y/d};
}
Double operator * (const Point &b)const{
return x*b.x + y*b.y;
}
Double operator % (const Point &b)const{
return x*b.y - y*b.x;
}
friend Double abs2(const Point &p){
return p.x*p.x + p.y*p.y;
}
friend Double abs(const Point &p){
return sqrt( abs2(p) );
}
};
typedef Point Vector;
struct Line{
Point P; Vector v;
bool operator < (const Line &b)const{
return atan2(v.y,v.x) < atan2(b.v.y,b.v.x);
}
};
```
### circumcentre
```C++=
#include "2Dpoint.cpp"
Point circumcentre(Point &p0, Point &p1, Point &p2){
Point a = p1-p0;
Point b = p2-p0;
Double c1 = abs2(a)*0.5;
Double c2 = abs2(b)*0.5;
Double d = a % b;
Double x = p0.x + ( c1*b.y - c2*a.y ) / d;
Double y = p0.y + ( c2*a.x - c1*b.x ) / d;
return {x,y};
}
```
### ConvexHull
```C++=
#include "2Dpoint.cpp"
// retunr H, 第 一 個 點 會 在 H 出 現 兩 次
void ConvexHull(vector<Point> &P, vector<Point> &H){
int n = P.size(), m=0;
sort(P.begin(),P.end());
H.clear();
for (int i=0; i<n; i++){
while (m>=2 && (P[i]-H[m-2]) % (H[m-1]-H[m-2])
<0)H.pop_back(), m--;
H.push_back(P[i]), m++;
}
for (int i=n-2; i>=0; i--){
while (m>=2 && (P[i]-H[m-2]) % (H[m-1]-H[m-2])
<0)H.pop_back(), m--;
H.push_back(P[i]), m++;
}
}
```
### 3D ConvexHull
```C++=
// return the faces with pt indexes
int flag[MXN][MXN];
struct Point{
ld x,y,z;
Point operator - (const Point &b) const {
return (Point){x-b.x,y-b.y,z-b.z};
}
Point operator * (const ld &b) const {
return (Point){x*b,y*b,z*b};
}
ld len() const { return sqrtl(x*x+y*y+z*z); }
ld dot(const Point &a) const {
return x*a.x+y*a.y+z*a.z;
}
Point operator * (const Point &b) const {
return (Point){y*b.z-b.y*z,z*b.x-b.z*x,x*b.y-b.x*y
};
}
};
Point ver(Point a, Point b, Point c) {
return (b - a) * (c - a);
}
vector<Face> convex_hull_3D(const vector<Point> pt) {
int n = SZ(pt);
REP(i,n) REP(j,n)
flag[i][j] = 0;
vector<Face> now;
now.push_back((Face){0,1,2});
now.push_back((Face){2,1,0});
int ftop = 0;
for (int i=3; i<n; i++){
ftop++;
vector<Face> next;
REP(j, SZ(now)) {
Face& f=now[j];
ld d=(pt[i]-pt[f.a]).dot(ver(pt[f.a], pt[f.b], pt
[f.c]));
if (d <= 0) next.push_back(f);
int ff = 0;
if (d > 0) ff=ftop;
else if (d < 0) ff=-ftop;
flag[f.a][f.b] = flag[f.b][f.c] = flag[f.c][f.a]
= ff;
}
REP(j, SZ(now)) {
Face& f=now[j];
if (flag[f.a][f.b] > 0 and flag[f.a][f.b] != flag
[f.b][f.a])
next.push_back((Face){f.a,f.b,i});
if (flag[f.b][f.c] > 0 and flag[f.b][f.c] != flag
[f.c][f.b])
next.push_back((Face){f.b,f.c,i});
if (flag[f.c][f.a] > 0 and flag[f.c][f.a] != flag
[f.a][f.c])
next.push_back((Face){f.c,f.a,i});
}
now=next;
}
return now;
}
```
### half plane intersection
```C++=
bool OnLeft(const Line& L,const Point& p){
return Cross(L.v,p-L.P)>0;
}
Point GetIntersection(Line a,Line b){
Vector u = a.P-b.P;
Double t = Cross(b.v,u)/Cross(a.v,b.v);
return a.P + a.v*t;
}
int HalfplaneIntersection(Line* L,int n,Point* poly){
sort(L,L+n);
int first,last;
Point *p = new Point[n];
Line *q = new Line[n];
q[first=last=0] = L[0];
for(int i=1;i<n;i++){
while(first < last && !OnLeft(L[i],p[last-1])) last
--;
while(first < last && !OnLeft(L[i],p[first])) first
++;
q[++last]=L[i];
if(fabs(Cross(q[last].v,q[last-1].v))<EPS){
last--;
if(OnLeft(q[last],L[i].P)) q[last]=L[i];
}
if(first < last) p[last-1]=GetIntersection(q[last
-1],q[last]);
}
while(first<last && !OnLeft(q[first],p[last-1])) last
--;
if(last-first <=1) return 0;
p[last]=GetIntersection(q[last],q[first]);
int m=0;
for(int i=first;i<=last;i++) poly[m++]=p[i];
return m;
}
```
### Intersection of two circle
```C++=
vector<Point> interCircle(Point o1, Double r1, Point o2
, Double r2) {
Double d2 = abs2(o1 - o2);
Double d = sqrt(d2);
Point u = (o1+o2)*0.5 + (o1-o2)*(r2*r2-r1*r1)/(2.0*d2
);
if (abs((r1+r2)*(r1+r2) - d2) < 1e-6) return {u};
if (d < fabs(r1-r2) || r1+r2 < d) return {};
Double A = sqrt((r1+r2+d) * (r1-r2+d) * (r1+r2-d) *
(-r1+r2+d));
Point v = Point{o1.y-o2.y, -o1.x+o2.x} * A / (2.0*d2)
;
return {u+v, u-v};
}
```
### Intersection of two lines
```C++=
Point interPnt(Point p1, Point p2, Point q1, Point q2,
bool &res){
Double f1 = cross(p2, q1, p1);
Double f2 = -cross(p2, q2, p1);
Double f = (f1 + f2);
if(fabs(f) < EPS) {
res = false;
return {};
}
res = true;
return (f2 / f) * q1 + (f1 / f) * q2;
}
```
### Smallest Circle
```C++=
#include "circumcentre.cpp"
pair<Point,Double> SmallestCircle(int n, Point _p[]){
Point *p = new Point[n];
memcpy(p,_p,sizeof(Point)*n);
random_shuffle(p,p+n);
Double r2=0;
Point cen;
for (int i=0; i<n; i++){
if ( abs2(cen-p[i]) <= r2)continue;
cen = p[i], r2=0;
for (int j=0; j<i; j++){
if ( abs2(cen-p[j]) <= r2)continue;
cen = (p[i]+p[j])*0.5;
r2 = abs2(cen-p[i]);
for (int k=0; k<j; k++){
if ( abs2(cen-p[k]) <= r2)continue;
cen = circumcentre(p[i],p[j],p[k]);
r2 = abs2(cen-p[k]);
}
}
}
delete[] p;
return {cen,r2};
}
// auto res = SmallestCircle(,);
```
## String
### AC automaton
```C++=
// remember make_fail() !!!
// notice MLE
const int sigma = 62;
const int MAXC = 200005;
inline int idx(char c){
if ('A'<= c && c <= 'Z')return c-'A';
if ('a'<= c && c <= 'z')return c-'a' + 26;
if ('0'<= c && c <= '9')return c-'0' + 52;
assert(false);
}
struct ACautomaton{
struct Node{
Node *next[sigma], *fail;
int cnt; // dp
Node() : next{}, fail{}, cnt{}{}
} buf[MAXC], *bufp, *ori, *root;
void init(){
bufp = buf;
ori = new (bufp++) Node();
root = new (bufp++) Node();
}
void insert(char *s){
Node *ptr = root;
for (int i=0; s[i]; i++){
int c = idx(s[i]);
if (!ptr->next[c])
ptr->next[c] = new (bufp++) Node();
ptr = ptr->next[c];
}
ptr->cnt=1;
}
Node* trans(Node *o, int c){
while (!o->next[c]) o = o->fail;
return o->next[c];
}
void make_fail(){
static queue<Node*> que;
for (int i=0; i<sigma; i++)
ori->next[i] = root;
root->fail = ori;
que.push(root);
while ( que.size() ){
Node *u = que.front(); que.pop();
for (int i=0; i<sigma; i++){
if (!u->next[i])continue;
u->next[i]->fail = trans(u->fail,i);
que.push(u->next[i]);
}
u->cnt += u->fail->cnt;
}
}
} ac;
```
### KMP
```C++=
template<typename T>
void build_KMP(int n, T *s, int *f){ // 1 base
f[0]=-1, f[1]=0;
for (int i=2; i<=n; i++){
int w = f[i-1];
while (w>=0 && s[w+1]!=s[i])w = f[w];
f[i]=w+1;
}
}
template<typename T>
int KMP(int n, T *a, int m, T *b){
build_KMP(m,b,f);
int ans=0;
for (int i=1, w=0; i<=n; i++){
while ( w>=0 && b[w+1]!=a[i] )w = f[w];
w++;
if (w==m){
ans++;
w=f[w];
}
}
return ans;
}
```
### palindromic tree
```C++=
// remember init() !!!
// remember make_fail() !!!
// insert s need 1 base !!!
// notice MLE
const int sigma = 62;
const int MAXC = 1000006;
inline int idx(char c){
if ('a'<= c && c <= 'z')return c-'a';
if ('A'<= c && c <= 'Z')return c-'A'+26;
if ('0'<= c && c <= '9')return c-'0'+52;
}
struct PalindromicTree{
struct Node{
Node *next[sigma], *fail;
int len, cnt; // for dp
Node(){
memset(next,0,sizeof(next));
fail=0;
len = cnt = 0;
}
} buf[MAXC], *bufp, *even, *odd;
void init(){
bufp = buf;
even = new (bufp++) Node();
odd = new (bufp++) Node();
even->fail = odd;
odd->len = -1;
}
void insert(char *s){
Node* ptr = even;
for (int i=1; s[i]; i++){
ptr = extend(ptr,s+i);
}
}
Node* extend(Node *o, char *ptr){
int c = idx(*ptr);
while ( *ptr != *(ptr-1-o->len) )o=o->fail;
Node *&np = o->next[c];
if (!np){
np = new (bufp++) Node();
np->len = o->len+2;
Node *f = o->fail;
if (f){
while ( *ptr != *(ptr-1-f->len) )f=f->
fail;
np->fail = f->next[c];
}
else {
np->fail = even;
}
np->cnt = np->fail->cnt;
}
np->cnt++;
return np;
}
} PAM;
```
### SAM
```C++=
// par : fail link
// val : a topological order ( useful for DP )
// go[x] : automata edge ( x is integer in [0,26) )
struct SAM{
struct State{
int par, go[26], val;
State () : par(0), val(0){ FZ(go); }
State (int _val) : par(0), val(_val){ FZ(go); }
};
vector<State> vec;
int root, tail;
void init(int arr[], int len){
vec.resize(2);
vec[0] = vec[1] = State(0);
root = tail = 1;
for (int i=0; i<len; i++)
extend(arr[i]);
}
void extend(int w){
int p = tail, np = vec.size();
vec.PB(State(vec[p].val+1));
for ( ; p && vec[p].go[w]==0; p=vec[p].par)
vec[p].go[w] = np;
if (p == 0){
vec[np].par = root;
} else {
if (vec[vec[p].go[w]].val == vec[p].val+1){
vec[np].par = vec[p].go[w];
} else {
int q = vec[p].go[w], r = vec.size();
vec.PB(vec[q]);
vec[r].val = vec[p].val+1;
vec[q].par = vec[np].par = r;
for ( ; p && vec[p].go[w] == q; p=vec[p].par)
vec[p].go[w] = r;
}
}
tail = np;
}
};
```
### smallest rotation
```C++=
string mcp(string s){
int n = s.length();
s += s;
int i=0, j=1;
while (i<n && j<n){
int k = 0;
while (k < n && s[i+k] == s[j+k]) k++;
if (s[i+k] <= s[j+k]) j += k+1;
else i += k+1;
if (i == j) j++;
}
int ans = i < n ? i : j;
return s.substr(ans, n);
}
```
### suffix array
```C++=
/*he[i]保 存 了 在 後 綴 數 組 中 相 鄰 兩 個 後 綴 的 最 ⻑ 公 共 前 綴 ⻑ 度
*sa[i]表 示 的 是 字 典 序 排 名 為i的 後 綴 是 誰 (字 典 序 越 小 的 排
名 越 靠 前)
*rk[i]表 示 的 是 後 綴 我 所 對 應 的 排 名 是 多 少 */
const int MAX = 1020304;
int ct[MAX], he[MAX], rk[MAX];
int sa[MAX], tsa[MAX], tp[MAX][2];
void suffix_array(char *ip){
int len = strlen(ip);
int alp = 256;
memset(ct, 0, sizeof(ct));
for(int i=0;i<len;i++) ct[ip[i]+1]++;
for(int i=1;i<alp;i++) ct[i]+=ct[i-1];
for(int i=0;i<len;i++) rk[i]=ct[ip[i]];
for(int i=1;i<len;i*=2){
for(int j=0;j<len;j++){
if(j+i>=len) tp[j][1]=0;
else tp[j][1]=rk[j+i]+1;
tp[j][0]=rk[j];
}
memset(ct, 0, sizeof(ct));
for(int j=0;j<len;j++) ct[tp[j][1]+1]++;
for(int j=1;j<len+2;j++) ct[j]+=ct[j-1];
for(int j=0;j<len;j++) tsa[ct[tp[j][1]]++]=j;
memset(ct, 0, sizeof(ct));
for(int j=0;j<len;j++) ct[tp[j][0]+1]++;
for(int j=1;j<len+1;j++) ct[j]+=ct[j-1];
for(int j=0;j<len;j++)
sa[ct[tp[tsa[j]][0]]++]=tsa[j];
rk[sa[0]]=0;
for(int j=1;j<len;j++){
if( tp[sa[j]][0] == tp[sa[j-1]][0] &&
tp[sa[j]][1] == tp[sa[j-1]][1] )
rk[sa[j]] = rk[sa[j-1]];
else
rk[sa[j]] = j;
}
}
for(int i=0,h=0;i<len;i++){
if(rk[i]==0) h=0;
else{
int j=sa[rk[i]-1];
h=max(0,h-1);
for(;ip[i+h]==ip[j+h];h++);
}
he[rk[i]]=h;
}
}
```
### Z value
```C++=
z[0] = 0;
for ( int bst = 0, i = 1; i < len ; i++ ) {
if ( z[bst] + bst <= i ) z[i] = 0;
else z[i] = min(z[i - bst], z[bst] + bst - i);
while ( str[i + z[i]] == str[z[i]] ) z[i]++;
if ( i + z[i] > bst + z[bst] ) bst = i;
}
// 回 文 版
void Zpal(const char *s, int len, int *z) {
// Only odd palindrome len is considered
// z[i] means that the longest odd palindrom
centered at
// i is [i-z[i] .. i+z[i]]
z[0] = 0;
for (int b=0, i=1; i<len; i++) {
if (z[b]+b >= i) z[i] = min(z[2*b-i], b+z[b]-i)
;
else z[i] = 0;
while (i+z[i]+1 < len && i-z[i]-1 >= 0 &&
s[i+z[i]+1] == s[i-z[i]-1]) z[i] ++;
if (z[i]+i > z[b]+b) b = i;
}
}
```
### BWT (Burrows-Wheeler Transform)
```C++=
string BWT(string); // by suffix array
string iBWT(string &s, int start=0){
int n = (int) s.size();
string ret(n,' ');
vector<int> next(n,0), box[256];
for (int i=0; i<n; i++) // bucket sort
box[ (int)s[i] ].push_back(i);
for (int i=0, j=0; i<256; i++)
for (int x:box[i])
next[j++] = x;
for (int i=0, p=start; i<n; i++)
ret[i] = s[ p=next[p] ];
return ret;
}
```
## Data structure
### 2D range tree
```C++=
// remember sort x !!!!!
typedef int T;
const int LGN = 20;
const int MAXN = 100005;
struct Point{
T x, y;
friend bool operator < (Point a, Point b){
return tie(a.x,a.y) < tie(b.x,b.y);
}
};
struct TREE{
Point pt;
int toleft;
}tree[LGN][MAXN];
struct SEG{
T mx, Mx;
int sz;
TREE *st;
}seg[MAXN*4];
vector<Point> P;
void build(int l, int r, int o, int deep){
seg[o].mx = P[l].x;
seg[o].Mx = P[r].x;
seg[o].sz = r-l+1;;
if(l == r){
tree[deep][r].pt = P[r];
tree[deep][r].toleft = 0;
seg[o].st = &tree[deep][r];
return;
}
int mid = (l+r)>>1;
build(l,mid,o+o,deep+1);
build(mid+1,r,o+o+1,deep+1);
TREE *ptr = &tree[deep][l];
TREE *pl = &tree[deep+1][l], *nl = &tree[deep+1][
mid+1];
TREE *pr = &tree[deep+1][mid+1], *nr = &tree[deep
+1][r+1];
int cnt = 0;
while(pl != nl && pr != nr) {
*(ptr) = pl->pt.y <= pr->pt.y ? cnt++, *(pl++):
*(pr++);
ptr -> toleft = cnt; ptr++;
}
while(pl != nl) *(ptr) = *(pl++), ptr -> toleft =
++cnt, ptr++;
while(pr != nr) *(ptr) = *(pr++), ptr -> toleft =
cnt, ptr++;
}
int main(){
int n; cin >> n;
for(int i = 0 ;i < n; i++){
T x,y; cin >> x >> y;
P.push_back((Point){x,y});
}
sort(P.begin(),P.end());
build(0,n-1,1,0);
}
```
### ext heap
```C++=
#include <bits/extc++.h>
typedef __gnu_pbds::priority_queue <int> heap_t;
heap_t a,b;
int main() {
a.clear();
b.clear();
a.push(1);
a.push(3);
b.push(2);
b.push(4);
assert(a.top() == 3);
assert(b.top() == 4);
// merge two heap
a.join(b);
assert(a.top() == 4);
assert(b.empty());
return 0;
}
```
### KD tree
```C++=
// from BCW
const int MXN = 100005;
struct KDTree {
struct Node {
int x,y,x1,y1,x2,y2;
int id,f;
Node *L, *R;
}tree[MXN];
int n;
Node *root;
long long dis2(int x1, int y1, int x2, int y2) {
long long dx = x1-x2;
long long dy = y1-y2;
return dx*dx+dy*dy;
}
static bool cmpx(Node& a, Node& b){ return a.x<b.x; }
static bool cmpy(Node& a, Node& b){ return a.y<b.y; }
void init(vector<pair<int,int>> ip) {
n = ip.size();
for (int i=0; i<n; i++) {
tree[i].id = i;
tree[i].x = ip[i].first;
tree[i].y = ip[i].second;
}
root = build_tree(0, n-1, 0);
}
Node* build_tree(int L, int R, int dep) {
if (L>R) return nullptr;
int M = (L+R)/2;
tree[M].f = dep%2;
nth_element(tree+L, tree+M, tree+R+1, tree[M].f ?
cmpy : cmpx);
tree[M].x1 = tree[M].x2 = tree[M].x;
tree[M].y1 = tree[M].y2 = tree[M].y;
tree[M].L = build_tree(L, M-1, dep+1);
if (tree[M].L) {
tree[M].x1 = min(tree[M].x1, tree[M].L->x1);
tree[M].x2 = max(tree[M].x2, tree[M].L->x2);
tree[M].y1 = min(tree[M].y1, tree[M].L->y1);
tree[M].y2 = max(tree[M].y2, tree[M].L->y2);
}
tree[M].R = build_tree(M+1, R, dep+1);
if (tree[M].R) {
tree[M].x1 = min(tree[M].x1, tree[M].R->x1);
tree[M].x2 = max(tree[M].x2, tree[M].R->x2);
tree[M].y1 = min(tree[M].y1, tree[M].R->y1);
tree[M].y2 = max(tree[M].y2, tree[M].R->y2);
}
return tree+M;
}
int touch(Node* r, int x, int y, long long d2){
long long dis = sqrt(d2)+1;
if (x<r->x1-dis || x>r->x2+dis || y<r->y1-dis || y>
r->y2+dis)
return 0;
return 1;
}
void nearest(Node* r, int x, int y, int &mID, long
long &md2) {
if (!r || !touch(r, x, y, md2)) return;
long long d2 = dis2(r->x, r->y, x, y);
if (d2 < md2 || (d2 == md2 && mID < r->id)) {
mID = r->id;
md2 = d2;
}
// search order depends on split dim
if ((r->f == 0 && x < r->x) ||
(r->f == 1 && y < r->y)) {
nearest(r->L, x, y, mID, md2);
nearest(r->R, x, y, mID, md2);
} else {
nearest(r->R, x, y, mID, md2);
nearest(r->L, x, y, mID, md2);
}
}
int query(int x, int y) {
int id = 1029384756;
long long d2 = 102938475612345678LL;
nearest(root, x, y, id, d2);
return id;
}
}tree;
```
### Link-Cut tree
```C++=
// from bcw codebook
const int MXN = 100005;
const int MEM = 100005;
struct Splay {
static Splay nil, mem[MEM], *pmem;
Splay *ch[2], *f;
int val, rev, size;
Splay () : val(-1), rev(0), size(0) {
f = ch[0] = ch[1] = &nil;
}
Splay (int _val) : val(_val), rev(0), size(1) {
f = ch[0] = ch[1] = &nil;
}
bool isr() {
return f->ch[0] != this && f->ch[1] != this;
}
int dir() {
return f->ch[0] == this ? 0 : 1;
}
void setCh(Splay *c, int d) {
ch[d] = c;
if (c != &nil) c->f = this;
pull();
}
void push() {
if (rev) {
swap(ch[0], ch[1]);
if (ch[0] != &nil) ch[0]->rev ^= 1;
if (ch[1] != &nil) ch[1]->rev ^= 1;
rev=0;
}
}
void pull() {
size = ch[0]->size + ch[1]->size + 1;
if (ch[0] != &nil) ch[0]->f = this;
if (ch[1] != &nil) ch[1]->f = this;
}
} Splay::nil, Splay::mem[MEM], *Splay::pmem = Splay::
mem;
Splay *nil = &Splay::nil;
void rotate(Splay *x) {
Splay *p = x->f;
int d = x->dir();
if (!p->isr()) p->f->setCh(x, p->dir());
else x->f = p->f;
p->setCh(x->ch[!d], d);
x->setCh(p, !d);
p->pull(); x->pull();
}
vector<Splay*> splayVec;
void splay(Splay *x) {
splayVec.clear();
for (Splay *q=x;; q=q->f) {
splayVec.push_back(q);
if (q->isr()) break;
}
reverse(begin(splayVec), end(splayVec));
for (auto it : splayVec) it->push();
while (!x->isr()) {
if (x->f->isr()) rotate(x);
else if (x->dir()==x->f->dir()) rotate(x->f),rotate
(x);
else rotate(x),rotate(x);
}
}
Splay* access(Splay *x) {
Splay *q = nil;
for (;x!=nil;x=x->f) {
splay(x);
x->setCh(q, 1);
q = x;
}
return q;
}
void evert(Splay *x) {
access(x);
splay(x);
x->rev ^= 1;
x->push(); x->pull();
}
void link(Splay *x, Splay *y) {
// evert(x);
access(x);
splay(x);
evert(y);
x->setCh(y, 1);
}
void cut(Splay *x, Splay *y) {
// evert(x);
access(y);
splay(y);
y->push();
y->ch[0] = y->ch[0]->f = nil;
}
int N, Q;
Splay *vt[MXN];
int ask(Splay *x, Splay *y) {
access(x);
access(y);
splay(x);
int res = x->f->val;
if (res == -1) res=x->val;
return res;
}
int main(int argc, char** argv) {
scanf("%d%d", &N, &Q);
for (int i=1; i<=N; i++)
vt[i] = new (Splay::pmem++) Splay(i);
while (Q--) {
char cmd[105];
int u, v;
scanf("%s", cmd);
if (cmd[1] == 'i') {
scanf("%d%d", &u, &v);
link(vt[v], vt[u]);
} else if (cmd[0] == 'c') {
scanf("%d", &v);
cut(vt[1], vt[v]);
} else {
scanf("%d%d", &u, &v);
int res=ask(vt[u], vt[v]);
printf("%d\n", res);
}
}
return 0;
}
```
### Treap Lin
```C++=
#include <bits/stdc++.h>
using namespace std;
const int INF = 1<<30;
int ran(){
static unsigned x = 20190223;
return x = 0xdefaced*x+1;
}
struct Treap{
Treap *l,*r;
int num,m,sz,tag,ra,ad;
Treap(int a){
l=r=0; num=m=a; sz=1; tag=ad=0;
ra = ran();
}
};
int size(Treap *a){
return a ? a->sz : 0;
}
int min(Treap *a){
return a ? a->m+a->ad : INF;
}
void push(Treap *a){
if(!a) return;
if(a->tag){
swap(a->l,a->r);
if(a->l)a->l->tag ^= 1;
if(a->r)a->r->tag ^= 1;
a->tag=0;
}
if(a->l)a->l->ad += a->ad;
if(a->r)a->r->ad += a->ad;
a->num += a->ad;
a->m += a->ad;
a->ad = 0;
}
void pull(Treap *a){
if(!a) return;
a->sz=1+size(a->l)+size(a->r);
a->m = min({ a->num, min(a->l), min(a->r) });
}
Treap* merge(Treap *a, Treap *b){
if(!a || !b) return a ? a : b;
if(a->ra > b->ra){
push(a);
a->r = merge(a->r,b);
pull(a);
return a;
}else{
push(b);
b->l = merge(a,b->l);
pull(b);
return b;
}
}
void split (Treap *o, Treap *&a, Treap *&b, int k){
if(!k) a=0, b=o;
else if(size(o)==k) a=o, b=0;
else{
push(o);
if(k <= size(o->l)){
b = o;
split(o->l, a, b->l,k);
pull(b);
}else{
a = o;
split(o->r, a->r, b, k-size(o->l)-1);
pull(a);
}
}
}
int main(){
Treap *head=0, *ta, *tb, *tc, *td;
int a, b, c, n; scanf("%d",&n);
for(int i=0; i<n; i++){
int t; scanf("%d",&t);
head = merge(head,new Treap(t));
}
int Q; scanf("%d",&Q);
char ss[50];
while(Q--){
scanf("%s",ss);
if(strcmp(ss,"ADD")==0){
scanf("%d%d%d",&a,&b,&c);
split(head,tb,tc,b);
split(tb,ta,tb,a-1);
tb -> ad += c;
head = merge(ta, merge(tb, tc));
}else if(strcmp(ss,"REVERSE")==0){
scanf("%d%d",&a,&b);
split(head,tb,tc,b);
split(tb,ta,tb,a-1);
tb -> tag ^= 1;
head = merge(ta, merge(tb, tc));
}else if(strcmp(ss,"REVOLVE")==0){
scanf("%d%d%d",&a,&b,&c);
split(head,tb,tc,b);
split(tb,ta,tb,a-1);
int szz = size(tb);
c %= szz;
split(tb,tb,td,szz-c);
tb=merge(td,tb);
head = merge(ta, merge(tb, tc));
}else if(strcmp(ss,"INSERT")==0){
scanf("%d%d",&a,&b);
split(head,ta,tc,a);
tb = new Treap(b);
head = merge(ta, merge(tb, tc));
}else if(strcmp(ss,"DELETE")==0){
scanf("%d",&a);
split(head,ta,tc,a-1);
split(tc,tb,tc,1);
delete tb;
head = merge(ta,tc);
}else if(strcmp(ss,"MIN")==0){
scanf("%d%d",&a,&b);
split(head,tb,tc,b);
split(tb,ta,tb,a-1);
printf("%d\n",min(tb));
head = merge(ta, merge(tb, tc));
}
}
}
```
## Other
### count spanning tree
#### 新 的 方 法 介 绍
下 面 我 们 介 绍 一 种 新 的 方 法 — — Matrix-Tree定 理(Kirchhoff矩阵-树 定 理)。
Matrix-Tree定 理 是 解 决 生 成 树 计 数 问 题 最 有 力 的 武 器 之 一。 它 首 先 于1847年 被Kirchhoff证 明。 在 介 绍 定 理 之 前, 我 们 首 先 明 确 几 个 概 念:
1、G的 度 数 矩 阵D[G]是 一 个n*n的 矩 阵, 并 且 满 足: 当i≠j时, dij=0; 当i=j时, dij等 于vi的 度 数。
2、G的 邻 接 矩 阵A[G]也 是 一 个n*n的 矩 阵, 并 且 满 足: 如 果vi、vj之 间 有 边 直 接 相 连, 则aij=1, 否 则 为0。
我 们 定 义G的Kirchhoff矩 阵(也 称 为 拉 普 拉 斯 算 子)C[G]为C[G]= D[G]-A[G],则Matrix-Tree定 理 可 以 描 述 为:G的 所 有 不 同 的 生 成 树 的 个 数 等 于 其Kirchhoff矩 阵C[G]任 何 一 个n-1阶 主 子 式 的 行 列 式 的 绝 对 值。 所 谓n-1阶 主 子 式, 就 是 对 于r(1≤r≤n), 将C[G]的 第r行、 第r列 同 时 去 掉 后 得 到 的 新 矩 阵, 用Cr[G]表 示。
#### 生 成 树 计 数
算 法 步 骤:
1、 构 建 拉 普 拉 斯 矩 阵
Matrix[i][j] =
degree(i) , i==j
-1,i-j有 边
0, 其 他 情 况
2、 去 掉 第r行, 第r列 (r任 意)
3、 计 算 矩 阵 的 行 列 式
```C++=
/* ***********************************************
MYID : Chen Fan
LANG : G++
PROG : Count_Spaning_Tree_From_Kuangbin
************************************************ */
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <math.h>
using namespace std;
const double eps = 1e-8;
const int MAXN = 110;
int sgn(double x)
{
if(fabs(x) < eps)return 0;
if(x < 0)return -1;
else return 1;
}
double b[MAXN][MAXN];
double det(double a[][MAXN],int n)
{
int i, j, k, sign = 0;
double ret = 1;
for(i = 0;i < n;i++)
for(j = 0;j < n;j++) b[i][j] = a[i][j];
for(i = 0;i < n;i++)
{
if(sgn(b[i][i]) == 0)
{
for(j = i + 1; j < n;j++)
if(sgn(b[j][i]) != 0) break;
if(j == n)return 0;
for(k = i;k < n;k++) swap(b[i][k],b[j][k]);
sign++;
}
ret *= b[i][i];
for(k = i + 1;k < n;k++) b[i][k]/=b[i][i];
for(j = i+1;j < n;j++)
for(k = i+1;k < n;k++) b[j][k] -= b[j][i]*b[i][
k];
}
if(sign & 1)ret = -ret;
return ret;
}
double a[MAXN][MAXN];
int g[MAXN][MAXN];
int main()
{
int T;
int n,m;
int u,v;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
memset(g,0,sizeof(g));
while(m--)
{
scanf("%d%d",&u,&v);
u--;v--;
g[u][v] = g[v][u] = 1;
}
memset(a,0,sizeof(a));
for(int i = 0;i < n;i++)
for(int j = 0;j < n;j++)
if(i != j && g[i][j])
{
a[i][i]++;
a[i][j] = -1;
}
double ans = det(a,n-1);
printf("%.0lf\n",ans);
}
return 0;
}
```
### C++11 random
```C++=
void init(){
std::random_device rd;
std::default_random_engine gen( rd() );
std::uniform_int_distribution <unsigned long long>
dis(0,ULLONG_MAX);
for (int i=0; i<MAXN; i++){
h[i] = dis(gen);
}
}
```
### Digit Counting
```C++=
int dfs(int pos, int state1, int state2 ....., bool
limit, bool zero) {
if ( pos == -1 ) return 是 否 符 合 條 件;
int &ret = dp[pos][state1][state2][....];
if ( ret != -1 && !limit ) return ret;
int ans = 0;
int upper = limit ? digit[pos] : 9;
for ( int i = 0 ; i <= upper ; i++ ) {
ans += dfs(pos - 1, new_state1, new_state2,
limit & ( i == upper), ( i == 0) && zero);
}
if ( !limit ) ret = ans;
return ans;
}
int solve(int n) {
int it = 0;
for ( ; n ; n /= 10 ) digit[it++] = n % 10;
return dfs(it - 1, 0, 0, 1, 1);
}
```
### DP optimization
#### Monotonicity & 1D/1D DP & 2D/1D DP
##### Definition xD/yD
1D/1D DP[j] = min(0≤i<j) { DP[i] + w(i, j) }; DP[0] = k
2D/1D DP[i][j] = min(i<k≤j) { DP[i][k - 1] + DP[k][j] }
+ w(i, j); DP[i][i] = 0
#### Monotonicity
c d
a | w(a, c) w(a, d)
b | w(b, c) w(b, d)
#### Monge Condition
Concave(凹 四 邊 形 不 等 式): w(a, c) + w(b, d) >= w(a, d) +
w(b, c)
Convex (凸 四 邊 形 不 等 式): w(a, c) + w(b, d) <= w(a, d) +
w(b, c)
Totally Monotone
Concave(凹 單 調): w(a, c) <= w(b, d) -----> w(a, d) <= w
(b, c)
Convex (凸 單 調): w(a, c) >= w(b, d) -----> w(a, d) >= w
(b, c)
#### 1D/1D DP O(n^2) -> O(nlgn)
*CONSIDER THE TRANSITION POINT*
Solve 1D/1D Concave by Stack
Solve 1D/1D Convex by Deque
#### 2D/1D Convex DP (Totally Monotone) O(n^3) -> O(n^2)
h(i, j − 1) ≤ h(i, j) ≤ h(i + 1, j)
### DP 1D/1D
```C++=
#include<bits/stdc++.h>
int t, n, L;
int p;
char s[MAXN][35];
ll sum[MAXN] = {0};
long double dp[MAXN] = {0};
int prevd[MAXN] = {0};
long double pw(long double a, int n) {
if ( n == 1 ) return a;
long double b = pw(a, n/2);
if ( n & 1 ) return b*b*a;
else return b*b;
}
long double f(int i, int j) {
// cout << (sum[i] - sum[j]+i-j-1-L) << endl;
return pw(abs(sum[i] - sum[j]+i-j-1-L), p) + dp[j];
}
struct INV {
int L, R, pos;
};
INV stk[MAXN*10];
int top = 1, bot = 1;
void update(int i) {
while ( top > bot && i < stk[top].L && f(stk[top].L
, i) < f(stk[top].L, stk[top].pos) ) {
stk[top - 1].R = stk[top].R;
top--;
}
int lo = stk[top].L, hi = stk[top].R, mid, pos =
stk[top].pos;
//if ( i >= lo ) lo = i + 1;
while ( lo != hi ) {
mid = lo + (hi - lo) / 2;
if ( f(mid, i) < f(mid, pos) ) hi = mid;
else lo = mid + 1;
}
if ( hi < stk[top].R ) {
stk[top + 1] = (INV) { hi, stk[top].R, i };
stk[top++].R = hi;
}
}
int main() {
cin >> t;
while ( t-- ) {
cin >> n >> L >> p;
dp[0] = sum[0] = 0;
for ( int i = 1 ; i <= n ; i++ ) {
cin >> s[i];
sum[i] = sum[i-1] + strlen(s[i]);
dp[i] = numeric_limits <long double>::max();
}
stk[top] = (INV) {1, n + 1, 0};
for ( int i = 1 ; i <= n ; i++ ) {
if ( i >= stk[bot].R ) bot++;
dp[i] = f(i, stk[bot].pos);
update(i);
// cout << (ll) f(i, stk[bot].pos) << endl;
}
if ( dp[n] > 1e18 ) {
cout << "Too hard to arrange" << endl;
} else {
vector<PI> as;
cout << (ll)dp[n] << endl;
}
}
return 0;
}
```
### Manhattan MST.cpp
```C++=
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100005;
const int OFFSET = 2000; // y-x may < 0, offset it, if
y-x too large, please write a unique function
const int INF = 0xFFFFFFF;
int n;
int x[MAXN], y[MAXN], p[MAXN];
typedef pair<int, int> pii;
pii bit[MAXN]; // [ val, pos ]
struct P {
int x, y, id;
bool operator<(const P&b ) const {
if ( x == b.x ) return y > b.y;
else return x > b.x;
}
};
vector<P> op;
struct E {
int x, y, cost;
bool operator<(const E&b ) const {
return cost < b.cost;
}
};
vector<E> edges;
int find(int x) {
return p[x] == x ? x : p[x] = find(p[x]);
}
void update(int i, int v, int p) {
while ( i ) {
if ( bit[i].first > v ) bit[i] = {v, p};
i -= i & (-i);
}
}
pii query(int i) {
pii res = {INF, INF};
while ( i < MAXN ) {
if ( bit[i].first < res.first ) res = {bit[i].
first, bit[i].second};
i += i & (-i);
}
return res;
}
void input() {
cin >> n;
for ( int i = 0 ; i < n ; i++ ) cin >> x[i] >> y[i
], op.push_back((P) {x[i], y[i], i});
}
void mst() {
for ( int i = 0 ; i < MAXN ; i++ ) p[i] = i;
int res = 0;
sort(edges.begin(), edges.end());
for ( auto e : edges ) {
int x = find(e.x), y = find(e.y);
if ( x != y ) {
p[x] = y;
res += e.cost;
}
}
cout << res << endl;
}
void construct() {
sort(op.begin(), op.end());
for ( int i = 0 ; i < n ; i++ ) {
pii q = query(op[i].y - op[i].x + OFFSET);
update(op[i].y - op[i].x + OFFSET, op[i].x + op
[i].y, op[i].id);
if ( q.first == INF ) continue;
edges.push_back((E) {op[i].id, q.second, abs(x[
op[i].id]-x[q.second]) + abs(y[op[i].id]-y[
q.second]) });
}
}
void solve() {
// [45 ~ 90 deg]
for ( int i = 0 ; i < MAXN ; i++ ) bit[i] = {INF,
INF};
construct();
// [0 ~ 45 deg]
for ( int i = 0 ; i < MAXN ; i++ ) bit[i] = {INF,
INF};
for ( int i = 0 ; i < n ; i++ ) swap(op[i].x, op[i
].y);
construct();
for ( int i = 0 ; i < n ; i++ ) swap(op[i].x, op[i
].y);
// [-90 ~ -45 deg]
for ( int i = 0 ; i < MAXN ; i++ ) bit[i] = {INF,
INF};
for ( int i = 0 ; i < n ; i++ ) op[i].y *= -1;
construct();
// [-45 ~ 0 deg]
for ( int i = 0 ; i < MAXN ; i++ ) bit[i] = {INF,
INF};
for ( int i = 0 ; i < n ; i++ ) swap(op[i].x, op[i
].y);
construct();
// mst
mst();
}
int main () {
input();
solve();
return 0;
}
```
### stable marriage
```C++=
// normal stable marriage problem
// input:
//3
//Albert Laura Nancy Marcy
//Brad Marcy Nancy
//Chuck Laura Marcy Nancy
//Laura Chuck Albert Brad
//Marcy Albert Chuck Brad
//Nancy Brad Albert Chuck
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 505;
int n;
int favor[MAXN][MAXN]; // favor[boy_id][rank] = girl_id
;
int order[MAXN][MAXN]; // order[girl_id][boy_id] = rank
;
int current[MAXN]; // current[boy_id] = rank; boy_id
will pursue current[boy_id] girl.
int girl_current[MAXN]; // girl[girl_id] = boy_id;
void initialize() {
for ( int i = 0 ; i < n ; i++ ) {
current[i] = 0;
girl_current[i] = n;
order[i][n] = n;
}
}
map<string, int> male, female;
string bname[MAXN], gname[MAXN];
int fit = 0;
void stable_marriage() {
queue<int> que;
for ( int i = 0 ; i < n ; i++ ) que.push(i);
while ( !que.empty() ) {
int boy_id = que.front();
que.pop();
int girl_id = favor[boy_id][current[boy_id]];
current[boy_id] ++;
if ( order[girl_id][boy_id] < order[girl_id][
girl_current[girl_id]] ) {
if ( girl_current[girl_id] < n ) que.push(
girl_current[girl_id]); // if not the first
time
girl_current[girl_id] = boy_id;
} else {
que.push(boy_id);
}
}
}
int main() {
cin >> n;
for ( int i = 0 ; i < n; i++ ) {
string p, t;
cin >> p;
male[p] = i;
bname[i] = p;
for ( int j = 0 ; j < n ; j++ ) {
cin >> t;
if ( !female.count(t) ) {
gname[fit] = t;
female[t] = fit++;
}
favor[i][j] = female[t];
}
}
for ( int i = 0 ; i < n ; i++ ) {
string p, t;
cin >> p;
for ( int j = 0 ; j < n ; j++ ) {
cin >> t;
order[female[p]][male[t]] = j;
}
}
initialize();
stable_marriage();
for ( int i = 0 ; i < n ; i++ ) {
cout << bname[i] << " " << gname[favor[i][current[i
] - 1]] << endl;
}
}
```
### Mo’s algorithm
```C++=
int l = 0, r = 0, nowAns = 0, BLOCK_SIZE, n, m;
int ans[];
struct QUE{
int l, r, id;
friend bool operator < (QUE a, QUE b){
if(a.l / BLOCK_SIZE != b.l / BLOCK_SIZE)
return a.l / BLOCK_SIZE < b.l / BLOCK_SIZE;
return a.r < b.r;
}
}querys[];
inline void move(int pos, int sign) {
// update nowAns
}
void solve() {
BLOCK_SIZE = int(ceil(pow(n, 0.5)));
sort(querys, querys + m);
for (int i = 0; i < m; ++i) {
const QUE &q = querys[i];
while (l > q.l) move(--l, 1);
while (r < q.r) move(r++, 1);
while (l < q.l) move(l++, -1);
while (r > q.r) move(--r, -1);
ans[q.id] = nowAns;
}
}
```
### Parser
```C++=
using LL = long long;
const int MAXLEVEL = 2;
// binary operators
const vector<char> Ops[MAXLEVEL] = {
{'+', '-'}, // level 0
{'*', '/'} // level 1
};
// unary operators
const vector<pair<char,int>> Op1s = {
{'-', 0} // operator negative works on level 0
};
struct Node{
~Node(){ delete L; delete R; }
enum { op, op1, num } type;
LL val;
Node *L, *R;
} *root;
char getOp1(int LEVEL, istream& is){
is >>ws;
for (auto& x : Op1s){
auto& op = x.first;
auto& lev = x.second;
if (LEVEL == lev && is.peek() == op)
return is.get();
}
return 0;
}
template <int LEVEL> void parse(Node*& x, istream& is){
char op1 = getOp1(LEVEL, is);
parse<LEVEL+1>(x, is);
if (op1) x = new Node{Node::op1, op1, x, nullptr};
auto& ops = Ops[LEVEL];
while (is>>ws && count(ops.begin(), ops.end(), is.
peek())){
x = new Node{Node::op, is.get(), x, nullptr};
parse<LEVEL+1>(x->R, is);
}
}
template <> void parse<MAXLEVEL >(Node*& x, istream& is)
{
char op1 = getOp1(MAXLEVEL, is);
is>>ws;
if (is.peek()>='0' && is.peek()<='9'){
LL t; is >>t;
x = new Node{Node::num, t, nullptr, nullptr};
} else if (is.peek() == '('){
is.get();
parse<0>(x, is);
is>>ws;
if (is.get()!=')') throw 0;
} else throw 0;
if (op1) x = new Node{Node::op1, op1, x, nullptr};
}
// throw when error occur !!!!!
void build(istream& is){
parse<0>(root, is);
if ((is>>ws).peek() != EOF) throw 0;
}
```
### java cheat sheet
```C++=
import java.util.*;
import java.math.*;
import java.io.*;
public class java{
static class Comp implements Comparator<Integer >{
public int compare(Integer lhs, Integer rhs){
return lhs - rhs;
}
}
static class Yee implements Comparable<Yee>{
public int compareTo(Yee y){
return 0;
}
}
static class Reader{
private BufferedReader br;
private StringTokenizer st;
public Reader(){
br = new BufferedReader(new
InputStreamReader(System.in));
}
boolean hasNext() throws IOException{
String s;
while (st == null || !st.hasMoreElements())
{
if ((s = br.readLine())==null) return
false;
st = new StringTokenizer(s);
}
return true;
}
String next() throws IOException{
while (st == null || !st.hasMoreElements())
st = new StringTokenizer(br.readLine())
;
return st.nextToken();
}
int nextInt() throws IOException{
return Integer.parseInt(next());
}// Long.parseLong, Double.parseDouble, br.
readLine
}
public static void main(String args[])throws
IOException{
Reader cin = new Reader();
//Scanner cin = new Scanner(System.in);
PrintWriter cout = new PrintWriter(System.out);
//Scanner cin = new Scanner(new File("t.in"));
//PrintWriter cout = new PrintWriter(new File("
t.out"));
// ***** cout.close() or cout.flush() is needed
*****
// 2D array: int[][] a = new int[10][10];
// input, EOF, Graph
int n = cin.nextInt();
// nextFloat, nextLine, next
ArrayList<ArrayList<Integer>> G = new ArrayList
<>();
for (int i=0; i<n; i++) G.add(new ArrayList <>()
);
while (cin.hasNext()){ // EOF
int u = cin.nextInt(), v = cin.nextInt();
G.get(u).add(v);
}
// Math: E, PI, min, max, random(double 0~1),
sin...
// Collections(List a): swap(a,i,j), sort(a[,
comp]), min(a), binarySearch(a,val[,comp])
// set
Set<Integer> set = new TreeSet <>();
set.add(87); set.remove(87);
if (!set.contains(87)) cout.println("no 87");
// map
Map<String, Integer> map = new HashMap <>();
map.put("0", 1); map.put("2", 3);
for ( Map.Entry<String,Integer> i : map.
entrySet() )
cout.println(i.getKey() + " " + i.getValue
() + " wry");
cout.println( map.get("1") );
// Big Number: TEN ONE ZERO, modInverse
isProbablePrime modInverse modPow
// add subtract multiply divide remainder, and
or xor not shiftLeft shiftRight
// queue: add, peek(==null), poll
PriorityQueue <Integer> pq = new PriorityQueue <
Integer >(Collections.reverseOrder());
Queue<Integer> q = new ArrayDeque<Integer >();
// stack: push, empty, pop
Stack<Integer> s = new Stack<Integer >();
cout.close();
}
}
```
### python cheat sheet
```C++=
#!/usr/bin/env python3
# import
import math
from math import *
import math as M
from math import sqrt
# input
n = int( input() )
a = [ int(x) for x in input().split() ]
# EOF
while True:
try:
solve()
except:
break;
# output
print( x, sep=' ')
print( ''.join( str(x)+' ' for x in a ) )
print( '{:5d}'.format(x) )
# sort
a.sort()
sorted(a)
# list
a = [ x for x in range(n) ]
a.append(x)
# Basic operator
a, b = 10, 20
a/b # 0.5
a//b # 0
a%b # 10
a**b # 10^20
# if, else if, else
if a==0:
print('zero')
elif a>0:
print('postive')
else:
print('negative')
# loop
while a==b and b==c:
for i in LIST:
# stack # C++
stack = [3,4,5]
stack.append(6) # push()
stack.pop() # pop()
stack[-1] # top()
len(stack) # size() O(1)
# queue # C++
from collections import deque
queue = deque([3,4,5])
queue.append(6) # push()
queue.popleft() # pop()
queue[0] # front()
len(queue) # size() O(1)
# random
from random import *
randrange(L,R,step) # [L,R) L+k*step
randint(L,R) # int from [L,R]
choice(list) # pick 1 item from list
choices(list,k) # pick k item
shuffle(list)
Uniform(L,R) # float from [L,R]
# Decimal
from fractions import Fraction
from decimal import Decimal, getcontext
getcontext().prec = 250 # set precision
itwo = Decimal(0.5)
two = Decimal(2)
N = 200
def angle(cosT):
"""given cos(theta) in decimal return theta"""
for i in range(N):
cosT = ((cosT + 1) / two) ** itwo
sinT = (1 - cosT * cosT) ** itwo
return sinT * (2 ** N)
pi = angle(Decimal(-1))
# file IO
r = open("filename.in")
a = r.read() # read whole content into one string
w = open("filename.out", "w")
w.write('123\n')
# IO redirection
import sys
sys.stdin = open('filename.in')
sys.stdout = open('filename.out', 'w')
```
### Segment tree
```C++=
void pull(int x){//合併左節點與右節點
total[x] = total[x<<1] + total[x<<1|1];
}
void build(int x, int l, int r){
if (l == r){
cin >> total[x];
return;
}
int mid = (l+r) >> 1;
build(x<<1, l, mid);
build(x<<1|1, mid+1, r);
pull(x);
}
int query(int x, int l, int r, int ql, int qr){
//[ql, qr]: 查詢區間
if (ql <= l && qr >= r){
return total[x];
}
int ret = 0;
int mid = (l+r)>>1;
if (ql <= mid){
ret += query(x<<1, l, mid, ql, qr);
}
if (qr > mid){
ret += query(x<<1|1, mid+1, r, ql, qr);
}
return ret;
}
void update(int x, int l, int r, int pos, int val){
if (l == r){
total[x] += val;
return;
}
int mid = (l+r) >> 1;
if (pos <= mid) update(x<<1, l, mid, pos, val);
else update(x<<1|1, mid+1, r, pos, val);
pull(x);
}
```
```C++=
const int N = 50010;
int n;
int w[N];
struct Node
{
int l, r;
int sum;
}tr[N * 4];
void pushup(int u)
{
tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
}
void build(int u, int l, int r)
{
if (l >= r) tr[u] = {l, r, w[r]};
else
{
tr[u] = {l, r};
int mid = l + r >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
pushup(u);
}
}
void modify(int u, int x, int v)
{
if (tr[u].l == x && tr[u].r == x) tr[u].sum += v;
else
{
int mid = tr[u].l + tr[u].r >> 1;
if (x <= mid) modify(u << 1, x, v);
else modify(u << 1 | 1, x, v);
pushup(u);
}
}
int query(int u, int l, int r)
{
if (tr[u].l >= l && tr[u].r <= r) return tr[u].sum;
else
{
int sum = 0;
int mid = tr[u].l + tr[u].r >> 1;
if (l <= mid) sum = query(u << 1, l, r);
if (r > mid) sum += query(u << 1 | 1, l, r);
return sum;
}
}
```
### Segment tree([Codeforce 339 problemD](https://codeforces.com/contest/339/problem/D))
```C++=
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#define ls rt<<1
#define rs rt<<1|1
using namespace std;
typedef long long ll;
const int maxn = 1e6+10;
int a[maxn],sum[maxn];
void pushup(int rt,int f) //樹的深度爲n+1 葉子結點不需要操作所以需要操作n次
{
if(f==1){
sum[rt] = sum[ls]|sum[rs];
// cout<<sum[ls]<<"和"<<sum[rs]<<"做or運算等於"<<sum[rt]<<"\n";
}
else{
sum[rt] = sum[ls]^sum[rs];
// cout<<sum[ls]<<"和"<<sum[rs]<<"做xor運算等於"<<sum[rt]<<"\n";
}
}
void build(int l,int r,int rt,int f)
{
if(l==r)
{
sum[rt] = a[l];
return ;
}
int m = (l+r)>>1;
build(l,m,ls,1-f);
build(m+1,r,rs,1-f);
pushup(rt,f);
}
void update(int p,int c,int l,int r,int rt,int f)
{
if(l==r)
{
sum[rt] = c;
return ;
}
int m = (l+r)>>1;
if(p<=m)
update(p,c,l,m,ls,1-f);
if(p>m)
update(p,c,m+1,r,rs,1-f);
pushup(rt,f);
}
int main()
{
int n,m;
int k;
scanf("%d%d",&n,&m);
k = (1<<n);
for(int i=1;i<=k;i++)
scanf("%d",&a[i]);
build(1,k,1,n%2); //保證從葉子節點開始的第一次操作爲 或 操作
for(int i=0;i<m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
update(x,y,1,k,1,n%2);
printf("%d\n",sum[1]);
}
return 0;
}
```
### Segment tree([d539: 區間 MAX](//https://zerojudge.tw/ShowProblem?problemid=d539))
```C++=
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
#define fastio ios::sync_with_stdio(false), cin.tie(NULL)
const int mxN = 5e5 + 5;
int n, st[mxN << 2];
void upd(int pos, int x, int v = 1, int l = 0, int r = n - 1) {
if(l == r) {
st[v] = x;
return;
}
int m = (l + r) >> 1;
if(pos <= m)
upd(pos, x, v << 1, l, m);
else
upd(pos, x, (v << 1) + 1, m + 1, r);
st[v] = max(st[v << 1], st[(v << 1) + 1]);
}
int qry(int l, int r, int v = 1, int L = 0, int R = n - 1) {
if(l == L && r == R)
return st[v];
int m = (L + R) >> 1;
if(r <= m)
return qry(l, r, v << 1, L, m);
else if(l > m)
return qry(l, r, (v << 1) + 1, m + 1, R);
return max(qry(l, m, v << 1, L, m), qry(m + 1, r, (v << 1) + 1, m + 1, R));
}
int main() {
fastio;
cin >> n;
for(int i = 0; i < n; ++i) {
int x;
cin >> x;
upd(i, x);
}
int q;
cin >> q;
while(q--) {
int l, r;
cin >> l >> r;
--l, --r;
if(l > r)
swap(l, r);
cout << qry(l, r) << "\n";
}
return 0;
}
```
# Dynamic Programming
## LCS
### <font color="#f00">2個字串的LCS:</font>
1. 回傳LCS的長度
```C++=
int LCS(const string& A, const string& B) {
vector<vector<int>> dp(A.size() + 1, vector<int>(B.size() + 1, 0));
for (int i{1}; i <= A.size(); ++i)
for (int j{1}; j <= B.size(); ++j) {
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
// 因為 A, B 是 0-indexed,透過 -1 調整
if (A[i - 1] == B[j - 1])
dp[i][j] = 1 + dp[i - 1][j - 1];
}
return dp[A.size()][B.size()];
}
```
2. 回傳LCS的字串
```C++=
string str_LCS(const string& A, const string& B) {
vector<vector<int>> dp(A.size() + 1, vector<int>(B.size() + 1, 0));
for (int i{1}; i <= A.size(); ++i)
for (int j{1}; j <= B.size(); ++j) {
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
// 因為 A, B 是 0-indexed,透過 -1 調整
if (A[i - 1] == B[j - 1])
dp[i][j] = 1 + dp[i - 1][j - 1];
}
string ans{};
int i = A.size(), j=B.size();
while (dp[i][j]) {
if (dp[i][j] == dp[i - 1][j]) --i;
else if (dp[i][j] == dp[i][j - 1]) --j;
else ans += A[i - 1], --i, --j;
// cout << "i:"<<i<<"j:"<<j<<" "<<ans<<"\n";
}
return reverse(ans.begin(), ans.end()), ans;
}
```
### <font color="#f00">3個字串的LCS:</font>
1. 回傳LCS的長度
```C++=
int LCS(const string& A, const string& B,const string& C) {
vector<vector<vector<int>>> dp(A.size()+1,vector<vector<int>>(B.size()+1,vector<int>(C.size()+1,0)));
for (int i{1}; i <= A.size(); ++i)
for (int j{1}; j <= B.size(); ++j)
for (int k{1}; k <= C.size(); ++k){
if(i-2 >= 0) dp[i-2].clear(); //為了不浪費memory
dp[i][j][k]=max({dp[i-1][j][k],dp[i][j-1][k],dp[i][j][k-1]});
if (A[i - 1] == B[j - 1] && A[i - 1] ==C[k-1] && A[i-1]!='?'){
dp[i][j][k] = 1 + dp[i - 1][j - 1][k-1];
}
}
return dp[A.size()][B.size()][C.size()];
}
```
##### Articulation Points 的數量
:::spoiler
```C++=
/**
* Articulation Points 的數量
*
*/
#include <bits/stdc++.h>
#include <numeric>
using namespace std;
typedef long long ll;
vector< vector<int> > edge;
vector<int> dfn, low;
int result, dep;
void dfs(int cur, int par)
{
bool cut = false;
int child = 0;
dfn[cur] = low[cur] = ++dep;
for (auto& i : edge[cur]) {
if (!dfn[i]) {
++child;
dfs(i, cur);
low[cur] = min(low[cur], low[i]);
if (low[i] >= dfn[cur]) cut = true;
}
else if (i != par) low[cur] = min(low[cur], dfn[i]);
}
if ((child >= 2 || par != -1) && cut) ++result;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N;
while (cin >> N && N) {
cin.ignore();
result = 0, dep = 0;
edge.assign(N + 1, vector<int>());
dfn.assign(N + 1, 0);
low.assign(N + 1, 0);
string str;
while (getline(cin, str)) {
stringstream ss(str);
int u, v;
ss >> u;
if (!u) break;
while (ss >> v) edge[v].emplace_back(u), edge[u].emplace_back(v);
}
dfs(1, -1);
cout << result << "\n";
}
return 0;
}
```
:::
---
# Week 12 Graph
## <font color="#f00"> 橋(bridge)</font>和 <font color="#f00"> 關節點(AP, articulation point, cut vertex)</font>
```C++=
#include<vector>
#include<iostream>
using namespace std;
vector<int> vis(100,0);
vector<int> dfn(100,0);
vector<int> low(100,0);
vector<int> parent(100,-1);
vector<bool> ap(100);
vector<pair<int,int>> bridge(100);
vector<vector<int>> adj(100);
int d=0;
int cnt=0;
void dfs(int u)
{
//记录dfs遍历次序
static int counter = 0;
//记录节点u的子树数
int children = 0;
vis[u] = true;
//初始化dfn与low
dfn[u] = low[u] = ++counter;
for (int j = 0; j < adj[u].size(); j++)//遍历与u相连的顶点
{
int v = adj[u][j];
if (!vis[v])
{
children++;
parent[v] = u;//u是v的父节点
dfs(v);//深度优先搜索v
low[u] = min(low[u], low[v]);//等v完成深度优先搜索之后,low[u]记录节点u或u的子树通过非父子边追溯到最早的祖先节点(即DFS次序号最小)
if (parent[u] == -1 && children > 1)//对根节点u,若其有两棵或两棵以上的子树,则该根结点u为割点;
{
//root如果大於2個child,就是articulation point
ap[u]=true;
}
if (parent[u] != -1 && low[v] >= dfn[u])//对非叶子节点u(非根节点),若其子树的节点均没有指向u的祖先节点的回边(条件low[v] >= dfn[u]表达的就是),说明删除u之后,根结点与u的子树的节点不再连通;则节点u为割点。
{
ap[u]=true;
}
if (low[v] >dfn[u]) //桥的条件
{
bridge.push_back(make_pair(u,v));
}
}else if (v != parent[u]) {//节点v已访问,则(u,v)为回边,且不是重边
low[u] = min(low[u], dfn[v]);
}
}
}
int main(){
int N=0;
while(cin>>N){
if(N==0) break;
int a;
while(cin >> a){
if(a==0) break;
int b;
while(cin>>b){
adj[a].push_back(b);
adj[b].push_back(a);
if(cin.get()=='\n') break ;
}
}
dfs(1);
for(int i=1;i<=N;i++){
if(ap[i]==1) cnt++;
}
cout<<"result:"<<cnt<<"\n";
}
}
```
:::
Computational_Geometry模板
:::spoiler
```C++=
struct Point{
double x, y;
Point(double x = 0, double y = 0) : x(x), y(y){}
Point operator+(const Point &b)const{ // vector addition
return Point(x + b.x, y + b.y);
}
Point operator-(const Point &b)const{ // vector subtraction
return Point(x - b.x, y - b.y);
}
Point operator*(double d)const{ // scale (multiplication)
return Point(x * d, y * d);
}
Point operator/(double d)const{ // scale (division)
return Point(x / d, y / d);
}
double dot(const Point &b)const{ // vector dot
return x * b.x + y * b.y;
}
double cross(const Point &b)const{ // vector cross
return x * b.y - y * b.x;
}
};
// premise: three points are collinear
bool btw(const Point &p1, const Point &p2, const Point &p3){
return (p1 - p3).dot(p2 - p3) <= 0;
}
bool collinearity(const Point &p1, const Point &p2, const Point &p3){
return (p1 - p3).cross(p2 - p3) == 0;
}
bool pointOnSegment(const Point &p1, const Point &p2, const Point &p3){
return collinearity(p1, p2, p3) && btw(p1, p2, p3);
}
int ori(const Point &p1, const Point &p2, const Point &p3){
double d = (p2 - p1).cross(p3 - p1);
if(d == 0)
return 0;
return d > 0 ? 1 : -1;
}
bool seg_intersect(const Point &p1, const Point &p2, const Point &p3, const Point &p4){
int a123 = ori(p1, p2, p3);
int a124 = ori(p1, p2, p4);
int a341 = ori(p3, p4, p1);
int a342 = ori(p3, p4, p2);
if(a123 == 0 && a124 == 0)
return btw(p1, p2, p3) || btw(p1, p2, p4) || btw(p3, p4, p1) || btw(p3, p4, p2);
return a123 * a124 <= 0 && a341 * a342 <= 0;
}
Point intersect(const Point &p1, const Point &p2, const Point &p3, const Point &p4){
int a123 = (p2 - p1).cross(p3 - p1);
int a124 = (p2 - p1).cross(p4 - p1);
return (p4 * a123 - p3 * a124) / (a123 - a124);
}
```
:::
## Week 15
``` C++=
struct Point{
double x, y;
Point(double x = 0, double y = 0) : x(x), y(y){}
Point operator+(const Point &b)const{ // 向量相加
return Point(x + b.x, y+b.y);
}
Point operator-(const Point &b)const{ // 向量相減
return Point(x - b.x, y- b.y);
}
Point operator*(double d)const{ // 伸長
return Point(x * d, y * d);
}
Point operator/(double d)const{ // 縮短
return Point(x / d, y / d);
}
double dot(const Point &b)const{ // 內積
return x * b.x + y * b.y;
}
double cross(const Point &b)const{ // 外積
return x * b.y - y * b.x;
}
bool btw(const Point &p1, const Point &p2, const Point &p3){ // 三點共線才能使用 -> 判斷點是否在線段內
return (p1 - p3).dot(p2 - p3) <= 0;
}
bool collinearity(const Point &p1, const Point &p2, const Point &p3){ // 判斷三點是否共線 -> 三角形之面積是否為 0
return (p1 - p3).cross(p2 - p3) == 0;
}
bool pointOnSegment(const Point &p1, const Point &p2, const Point &p3){ // 判斷 𝑃_3 是否在線段 (𝑃_1,𝑃_2) 中
return collinearity(p1, p2, p3) && btw(p1, p2, p3);
}
int ori(const Point &p1, const Point &p2, const Point &p3){ // 有向面積正負
double d = (p2 - p1).cross(p3 - p1);
if(d == 0)
return 0;
return d > 0 ? 1 : -1;
}
bool seg_intersect(const Point &p1, const Point &p2, const Point &p3, const Point &p4){ // 判斷線段相交
int a123 = ori(p1, p2, p3);
int a124 = ori(p1, p2, p4);
int a341 = ori(p3, p4, p1);
int a342 = ori(p3, p4, p2);
if(a123 == 0 && a124 == 0)
return btw(p1, p2, p3) || btw(p1, p2, p4) || btw(p3, p4, p1) || btw(p3, p4, p2);
return a123 * a124 <= 0 && a341 * a342 <= 0;
}
Point intersect(const Point &p1, const Point &p2, const Point &p3, const Point &p4){ // 找出直線交點
int a123 = (p2 - p1).cross(p3 - p1);
int a124 = (p2 - p1).cross(p4 - p1);
return (p4 * a123 - p3 * a124) / (a123 - a124);
}
bool cmp(const Point &a, const Point &b){
return (a.x < b.x) || (a.x == b.x && a.y < b.y);
}
vector<Point> convexHull(vector<Point> v){ // 找出凸包
int sz = 0;
vector<Point> ans;
sort(v.begin(), v.end(), cmp);
for(size_t i = 0; i < v.size(); i++){
while(sz >= 2 && (ans[sz - 1] - ans[sz - 2]).cross(v[i]- ans[sz - 2]) <= 0)
ans.pop_back(), sz--;
ans.push_back(v[i]), sz++;
}
for(int i = int(v.size()) - 2, t = sz + 1; i >= 0; i--){
while(sz >= 2 && (ans[sz - 1] - ans[sz - 2]).cross(v[i]- ans[sz - 2]) <= 0)
ans.pop_back(), sz--;
ans.push_back(v[i]), sz++;
}
ans.pop_back();
return ans;
}
double rotatingCaliper(const vector<Point> &v){
double ans = 0;
for(int i = 0, j = 0; i < v.size(); i++){
while(abs2(v[i], v[j]) <= abs2(v[i], v[(j + 1) % v.size()]))
j = (j + 1) % v.size();
ans = abs2(v[i], v[j]);
}
return sqrt(ans);
}
}; struct Point{
double x, y;
Point(double x = 0, double y = 0) : x(x), y(y){}
Point operator+(const Point &b)const{ // 向量相加
return Point(x + b.x, y+b.y);
}
Point operator-(const Point &b)const{ // 向量相減
return Point(x - b.x, y- b.y);
}
Point operator*(double d)const{ // 伸長
return Point(x * d, y * d);
}
Point operator/(double d)const{ // 縮短
return Point(x / d, y / d);
}
double dot(const Point &b)const{ // 內積
return x * b.x + y * b.y;
}
double cross(const Point &b)const{ // 外積
return x * b.y - y * b.x;
}
bool btw(const Point &p1, const Point &p2, const Point &p3){ // 三點共線才能使用 -> 判斷點是否在線段內
return (p1 - p3).dot(p2 - p3) <= 0;
}
bool collinearity(const Point &p1, const Point &p2, const Point &p3){ // 判斷三點是否共線 -> 三角形之面積是否為 0
return (p1 - p3).cross(p2 - p3) == 0;
}
bool pointOnSegment(const Point &p1, const Point &p2, const Point &p3){ // 判斷 𝑃_3 是否在線段 (𝑃_1,𝑃_2) 中
return collinearity(p1, p2, p3) && btw(p1, p2, p3);
}
int ori(const Point &p1, const Point &p2, const Point &p3){ // 有向面積正負
double d = (p2 - p1).cross(p3 - p1);
if(d == 0)
return 0;
return d > 0 ? 1 : -1;
}
bool seg_intersect(const Point &p1, const Point &p2, const Point &p3, const Point &p4){ // 判斷線段相交
int a123 = ori(p1, p2, p3);
int a124 = ori(p1, p2, p4);
int a341 = ori(p3, p4, p1);
int a342 = ori(p3, p4, p2);
if(a123 == 0 && a124 == 0)
return btw(p1, p2, p3) || btw(p1, p2, p4) || btw(p3, p4, p1) || btw(p3, p4, p2);
return a123 * a124 <= 0 && a341 * a342 <= 0;
}
Point intersect(const Point &p1, const Point &p2, const Point &p3, const Point &p4){ // 找出直線交點
int a123 = (p2 - p1).cross(p3 - p1);
int a124 = (p2 - p1).cross(p4 - p1);
return (p4 * a123 - p3 * a124) / (a123 - a124);
}
bool cmp(const Point &a, const Point &b){
return (a.x < b.x) || (a.x == b.x && a.y < b.y);
}
vector<Point> convexHull(vector<Point> v){ // 找出凸包
int sz = 0;
vector<Point> ans;
sort(v.begin(), v.end(), cmp);
for(size_t i = 0; i < v.size(); i++){
while(sz >= 2 && (ans[sz - 1] - ans[sz - 2]).cross(v[i]- ans[sz - 2]) <= 0)
ans.pop_back(), sz--;
ans.push_back(v[i]), sz++;
}
for(int i = int(v.size()) - 2, t = sz + 1; i >= 0; i--){
while(sz >= 2 && (ans[sz - 1] - ans[sz - 2]).cross(v[i]- ans[sz - 2]) <= 0)
ans.pop_back(), sz--;
ans.push_back(v[i]), sz++;
}
ans.pop_back();
return ans;
}
double rotatingCaliper(const vector<Point> &v){
double ans = 0;
for(int i = 0, j = 0; i < v.size(); i++){
while(abs2(v[i], v[j]) <= abs2(v[i], v[(j + 1) % v.size()]))
j = (j + 1) % v.size();
ans = abs2(v[i], v[j]);
}
return sqrt(ans);
}
};
```
### X-Magic Pair (CF1612)
``` C++=
#include <bits/stdc++.h>
#define yes puts("yes");
#define inf 0x3f3f3f3f
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define debug(x) cout<<"> "<< x<<endl;
#define ull unsigned long long
#define endl '\n'
#define lowbit(x) x&-x
//#define int long long
using namespace std;
typedef pair<int,int> PII;
const int N =10 + 1e5 ,mod=1e9 + 7;
void solve()
{
ll a,b,x;
cin>>a>>b>>x;
bool ok =0;
while(a && b){
if(a>b)swap(a,b);
if(b >= x&& (x-b%a) % a == 0) ok = 1;
b %= a;
}
cout << (ok?"YES":"NO") << endl;
}
signed main()
{
ios::sync_with_stdio();cin.tie();cout.tie();
int T;cin>>T;
while(T--)
solve();
return 0;
}
```
### d271: 11582 - Colossal Fibonacci Numbers!
``` c++
#include <iostream>
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
using namespace std;
typedef unsigned long long ULL;
const int UP = 1000 + 5;
int f[UP][UP*3], period[UP];
int qmod(ULL a, ULL b, ULL n) { // 快速冪模
a %= n;
ULL res = 1;
while(b) {
if(b & 1) res = res * a % n;
b >>= 1;
a = a * a % n;
}
return res;
}
int main() {
period[1] = 1;
for(int n = 2; n <= 1000; n++) {
f[n][0] = 0; f[n][1] = 1;
for(int i = 2; ; i++) {
f[n][i] = (f[n][i-1] + f[n][i-2]) % n;
if(f[n][i-1] == 0 && f[n][i] == 1) {
period[n] = i - 1;
break;
}
}
}
int T, n;
ULL a, b;
cin >> T;
while(T--) {
cin >>a>>b>>n;
int p = qmod(a, b, period[n]);
printf("%d\n", f[n][p]);
}
return 0;
}
```
### Problem for Nazar(CF1151)
```
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
ll quickmul(ll a,ll b)//b個a相乘,即a*b
{
ll ans=0;
while(b)
{
if(b&1)
ans=(ans+a)%mod;
a=(a+a)%mod;
b>>=1;
}
return ans;
}
ll sum(ll x)
{
ll num=0,even=0,odd=0;
while(x>0)
{
if(num%2)
even+=min(x, (ll)1<<num);
else
odd+=min(x, (ll)1<<num);
x-=(ll)1<<num;
num++;
}
return (quickmul(odd,odd)+quickmul(even,even+1))%mod;
}
int main()
{
ll L,R;
cin>>L>>R;
cout<<(sum(R)-sum(L-1)+mod)%mod<<endl;
return 0;
}
```
### MaxFlow
``` C++=
// C++ program for implementation of Ford Fulkerson algorithm
#include <iostream>
#include <limits.h>
#include <string.h>
#include <queue>
using namespace std;
// Number of vertices in given graph
#define V 6
/* Returns true if there is a path from source 's' to sink 't' in
residual graph. Also fills parent[] to store the path */
bool bfs(int rGraph[V][V], int s, int t, int parent[])
{
// Create a visited array and mark all vertices as not visited
bool visited[V];
memset(visited, 0, sizeof(visited));
// Create a queue, enqueue source vertex and mark source vertex as visited
queue<int> q;
q.push(s);
visited[s] = true;
parent[s] = -1;
// Standard BFS Loop
int u;
while (!q.empty())
{
// edge: u -> v
u = q.front(); // head point u
q.pop();
for (int v = 0; v < V; ++v) // tail point v
{
if (!visited[v] && rGraph[u][v] > 0) // find one linked vertex
{
q.push(v);
parent[v] = u; // find pre point
visited[v] = true;
}
}
}
// If we reached sink in BFS starting from source, then return true, else false
return visited[t] == true;
}
// Returns the maximum flow from s to t in the given graph
int fordFulkerson(int graph[V][V], int s, int t)
{
int u, v;
int rGraph[V][V];
for (u = 0; u < V; ++u)
{
for (v = 0; v < V; ++v)
{
rGraph[u][v] = graph[u][v];
}
}
int parent[V];
int max_flow = 0;
// Augment the flow while tere is path from source to sink
while (bfs(rGraph, s, t, parent))
{
// edge: u -> v
int path_flow = INT_MAX;
for (v = t; v != s; v = parent[v])
{
// find the minimum flow
u = parent[v];
path_flow = min(path_flow, rGraph[u][v]);
}
// update residual capacities of the edges and reverse edges along the path
for (v = t; v != s; v = parent[v])
{
u = parent[v];
rGraph[u][v] -= path_flow;
rGraph[v][u] += path_flow; // assuming v->u weight is add path_flow
}
// Add path flow to overall flow
max_flow += path_flow;
}
return max_flow;
}
int main()
{
int graph[V][V] = { {0,16,13, 0, 0, 0},
{0, 0,10,12, 0, 0},
{0, 4, 0, 0,14, 0},
{0, 0, 9, 0, 0,20},
{0, 0, 0, 7, 0, 4},
{0, 0, 0, 0, 0, 0}
};
cout << "the maximum flow from v0 to v5 is:" << endl << fordFulkerson(graph, 0, 5);
return 0;
}
```