# ㄌㄌㄎ的魔法書
## vim ~/.vimrc
```
syntax on
set cin nu si ai ic ts=4 sw=4 bs=2 bg=dark
inoremap {<CR> {<CR><END><CR>}<UP><END>
```
## 0.cpp
```
#include <bits/stdc++.h>
using namespace std;
#define INITIO() (ios::sync_with_stdio(0), cin.tie(0))
#define MEM(i,j) memset(i,j,sizeof i);
#define X first
#define Y second
#define pb push_back
#define mp make_pair
#define ALL(a) a.begin(),a.end()
typedef long long ll;
typedef long long Int;
typedef pair<int ,int> pii;
const double Eps = 1e-8;
const ll Inf = 1e18+7;
const int Mod = 1e9+7;
void solve(){
}
int main (){
INITIO();
int tt;
cin >> tt;
while (tt--) {
solve();
}
return 0;
}
```
## DSU
```
void ini(){
for(int i=0;i<N;i++) d[i]=i;
}
int find(ll v){
if(d[v]==v) return v;
return d[v] = find(d[v]);
}
void union(ll a,ll b){
d[find(a)] = find(b);
}
```
## MST
```
typedef struct{
ll a,b,w;
}Edge;
```
### Kruskal
$O(Elog(E))$
```
bool cmp(Edge a,Edge b){
return a.w<b.w;
}
Edge e[M];
ll d[N];
...
sort(e,e+m,cmp);
for(int j=0;j<m;j++){
if(find(e[j].a) == find(e[j].b)) continue;
d[find(e[j].a)] = find(e[j].b);
cost+=e[j].w;
MST.pb(Edge(e[j].a,e[j].b,w));
}
```
### Prim's
$O((E+N)log(E+N))$
```
priority_queue<Edge> q;
q.push((Edge){1,1,0}); //root
while(q.size()){
int a = (q.top()).a, b = (q.top()).b, w = (q.top()).w;
q.pop();
if(!vis[b]){
cost += w;
MST.pb(Edge(a,b,w));
for (auto it : E[b]) if(!vis[it.n]) q.push(Edge(b,it.n.it.w));
}
vis[b] = true;
}
```
## Segments tree
```
struct Seg {
int l, r, m;
Int mx;
Seg* ch[2];
Seg (int _l, int _r, vI &a) : l(_l), r(_r), m((l + r)/2) {
if (r - l > 1) {
ch[0] = new Seg(l, m, a);
ch[1] = new Seg(m, r, a);
mx=max(ch[0]->mx,ch[1]->mx);
} else {
mx = a[l];
}
}
Int query(Int ql , Int qr){
if (ql <= l && r <= qr) return mx;
Int ans=0;
if(qr<=m) ans = ch[0]->query(ql,qr);
else if(ql>=m) ans = ch[1]->query(ql,qr);
else ans = max(ch[0]->query(ql,m),ch[1]->query(m,qr));
return ans;
}
void modify(Int x , Int v){
if(r-l==1) {
mx = v;
return;
}
if(x<m) ch[0]->modify(x,v);
else ch[1]->modify(x,v);
mx=max(ch[0]->mx,ch[1]->mx);
}
};
```
## Dijkstra
單點搜尋
$O((E+N)log(N))$
```
struct Node{
ll n,w;
bool operator<(const node &lhs) const {
return lhs.w < w; //min heap
}
};
```
初始:
```
MEM(dist,Inf); //不連通設Inf
MEM(vis,false); //沒有拜訪
priority_queue<Node> q;
q.push((Node){1,dist[1]=0}); //看起點更改
```
循環:
```
while(q.size()){
node now = q.top();q.pop();
vis[now.n] = true;
for(auto nxt : e[now.n]){
if(vis[nxt.n]) continue;
const int &updater = dist[now.n] + nxt.w;
if(update < dist[nxt.n]) {
dist[nxt.n] = update; //鬆弛
q.push((Node){nxt.n,dist[nxt.n]});
}
}
}
```
## Bellman-Ford+檢查負環
單點搜尋
$O(NE)$
```
int w[N][N];
int d[N];
int parent[N];
void bellman_ford(int source){
for(int i=0;i<n;i++) d[i]=Inf;
d[source] = 0;
parent[source] = source;
for(int i=0;i<n-1;i++)
for(int a=0;a<n;++a)
for(int b=0;b<n;b++)
if(d[a] != Inf && w[a][b] != Inf)
if(d[a]+w[a][b] < d[b]){
d[b] = d[a] + w[a][b];
parent[b] = a;
}
}
```
負環檢查
* 如果還能鬆弛代表有負環
```
bool is_negative(){
for(int a=0;a<n;++a)
for(int b=0;b<n;++b)
if(d[a] != Inf && w[a][b] != Inf)
if(d[a]+w[a][b] < d[b])
return true;
return false;
}
```
遞迴版本 視情況修改 (一開始刻我以為是 dijkstra,但能處理處理負環)
```
ll bell(int start,int end,int val){
ll ans = Inf;
if(dis[start]<=val) return Inf;
else dis[start] = val;
if(start == end) return val;
for(int i=0;i<E[start].size();i++)
ans = min(ans,bell(E[start][i].X,end,E[start][i].Y+val));
return ans;
}
```
## Floyd-Warshell + 檢查負環
$O(N^3)$
多源搜尋
```
for(int i = 0;i<n ;i++){
for(int j =0;j<n ;j++){
if(i == j) dp[i][j] = 0;
else dp[i][j] = Inf;
}
}
...
for(int k =0;k<n;k++)
for(int i=0;i<n;i++)
for(int j = 0;j <n;j++)
dp[i][j] = min(dp[i][j],dp[i][k]+dp[k][j]);
```
負環
```
bool is_negative(){
for (int i=0; i<n; i++)
if (d[i][i] < 0) //自己到自己必須是0否則有負環
return true;
return false;
}
```
## AP 關節點
```
void dfs(int prec,int cur,int dep){
lvl[cur] = top[cur] = dep+1;
int child = 0;
for(itn nxt = 1;nxt <= n ; nxt++) if(E[cur][nxt] && nxt!= prev){
if(!lvl[nxt]){
child++,dfs(cur,nxt,dep+1);
if(dep && top[nxt] >= lvl[cur]) AP.insert(cur);
else top[cur] = min(top[cur],top[nxt]);
}else top[cur] = min(top[cur],lvl[nxt]);
}
}
```
## Max flow
```
int max_flow = 0;
while(1){
MEM(vis,false);
MEM(flow,false);
queue<int> q;
q.push(s); vis[s] = true; flow[s] = Inf;
while(q.size()){
int u=q.front();q.pop();
for(int v=s;v<=t;v++) if(R[u][v] && !vis[v]){
q.push(v);vis[v] = true;
flow[v] = min(flow[u],R[u][v]);
pre[v]=u;
}
}
if(flow[t]==0) break;
for(int v=t;v!=s;v=pre[v]){
int u = pre[v];
R[u][v] -= flow[t];
R[v][u] += flow[t];
}max_flow += flow[t];
}
```
## SCC
強連通 : 每個頂點皆能經由該圖邊抵達其他的每一個點的有向圖
```
void forward(int u){
vis[u] = true;
for(int v = 0;v < maxn;v++) if(E[u][v] && !vis[v]) forward(v);
st.push(u);
}
void backward(){
vis[u] = true;
for(int v=0;v<maxn;v++) if(E[u][v] && !vis[v]) backward(v);
}
```
循環
```
for(int u=0;u<n;u++) if(!vis[u]) forward(u);
MEM(vis,0);
int cnt = 0;
while(!st.empty()){
int node = st.top(); st.pop();
if(!vis[node]) cnt++,backward(node);
}
```
## 快速冪
```
ll Power(ll n,ll time){
ll a = 1;
while(time){
if(time & 1) a = a*n % Mod;
n = n*n % Mod;
time>>=1;
}
return a;
}
```
## 線性篩法
```
bool arr[n+1];
for(int i=2;i*i<=n;++i)
if(!arr[i])
for(int j = i*i ; j<=n ;j+=i)
arr[j] = true;
```
## KMP
找到 b 字串在 a 字串的最小位置
```
int pmatch(string a,string b){
int i=0,p=-1;
while(i<a.length()&&p+1<b.length()){
if(a[i]==b[p+1]){i++;p++;}
else if(p==-1) i++;
else p = f[p];
}
return (p+1 == b.length()?i-b.length():-1);
}
void fail(string pat){
int p = f[0] =-1;
for(int i=1;i<pat.length();i++){
while(p!=-1 && pat[i]!=pat[p+1]) p=f[p];
if(pat[p+1]==pat[i]) p++;
f[i] = p;
}
}
```
## GCD
```
int gcd(int a, int b)
{ return a? gcd(b%a, a) : b;}
```
### 貝祖等式 (Bezout’s Thm)
>對整數 **a,b** , 存在整數 **x,y** 使得 **ax+by = gcd(a,b)**
### 擴展歐基里德
令 **g = gcd(0,g) = gcd(a,b)**
```
int gcd(int a, int b, int &x, int &y) {
if(!a) {
x = 0; // x 為任意整數
y = 1;
return b;
}
int g = gcd(b%a, a, x, y);
int xp = y - b/a * x, yp = x; // p := previous
x = xp, y = yp;
return g;
}
```
**exgcd** 可求模反元素 x, 但僅於 a 跟 b 互質