diff --git a/Codebook.tex b/Codebook.tex index 73be78a..41defb6 100644 --- a/Codebook.tex +++ b/Codebook.tex @@ -110,4 +110,5 @@ \tableofcontents \end{multicols} \clearpage + \end{document} \ No newline at end of file diff --git a/VIM/3_tips.tex b/VIM/3_tips.tex index 10d31c9..dd2d932 100644 --- a/VIM/3_tips.tex +++ b/VIM/3_tips.tex @@ -1,9 +1,10 @@ \begin{itemize} \setlength\itemsep{-0.5em} - \item Segment Tree, DP, bitwise DP, 枚舉, 枚舉+剪枝, Disjoint Set - \item Priority Queue, 單調隊列, Prefix Sum, 偏序 + \item Segment Tree, DP, bitwise DP, 配合ds加速dp, 枚舉, 枚舉+剪枝, branch and bound, binarysearch, meet in middle + \item Priority Queue, 單調隊列, Prefix Sum, 偏序, 斜率優化, cdq, Disjoint Set \item Graph: SCC, AP, Bridge, LCA, 2-SAT - \item Flow, Min-cost Max-flow, Bipartite - \item Primal test, PollardRho, KMP, Rabin Fingerprint, FFT - \item Convex Hull, 旋轉卡尺, 極角排序 + \item Flow, Min-cost Max-flow, Bipartite, Cover, Matching + \item Flow 相關技巧 : increment capacity one by one, binary search on Constructing limit. 倍增點並計算貢獻值(WF: memory), 把點拆成in, out兩個點。 + \item Primal test, PollardRho, KMP, Rabin Fingerprint(BIT), FFT + \item Convex Hull, 旋轉卡尺, 極角排序, slicing, relabel \end{itemize} diff --git a/data_structure/Li_Chao_Tree.cpp b/data_structure/Li_Chao_Tree.cpp index 7bb2c95..50570a7 100644 --- a/data_structure/Li_Chao_Tree.cpp +++ b/data_structure/Li_Chao_Tree.cpp @@ -1,52 +1,83 @@ // Miminimum Li Chao Tree -typedef long long ftype; -typedef complex point; -#define x real -#define y imag - -ftype dot(point a, point b) { - return (conj(a) * b).x(); -} - -ftype f(point a, ftype x) { - return dot(a, {x, 1}); -} - -const int maxn = 2e5; - -point line[4 * maxn]; - +const ll inf = 1e18; +const int maxx = 1e6; +struct line +{ + ll m, b; + line() { m = b = inf; } + line(ll mm, ll bb){m = mm, b = bb;} + ll y(ll x){ + if(m == inf || b == inf) + return inf; + return m * x + b; + } +}; +line segs[4 * maxx]; /* a line is y = k * x + b, using point to represent it. -y = (k, b) * (x, 1) (dot operation). */ -// y = nw.real() * x + nw.imag(). -void add_line(point nw, int idx = 1, int l = 0, int r = maxn) +void add_line(line cur, int idx = 1, int l = 0, int r = maxx) { - int m = (l + r) / 2; - bool lef = f(nw, l) < f(line[idx], l); - bool mid = f(nw, m) < f(line[idx], m); - if(mid) { - swap(line[idx], nw); - } - if(r - l == 1) { + if(l == r){ + if(cur.y(l) < segs[idx].y(l)){ + segs[idx] = cur; + } return; - } else if(lef != mid) { - add_line(nw, 2 * idx, l, m); - } else { - add_line(nw, 2 * idx + 1, m, r); + } + int mid = (l + r) >> 1; + if(cur.m > segs[idx].m){ + swap(cur, segs[idx]); + } + if(cur.y(mid) < segs[idx].y(mid)){ + swap(cur, segs[idx]); + add_line(cur, idx * 2, l, mid); + } + else{ + add_line(cur, idx * 2 + 1, mid + 1, r); } } -// get minimum in some point x; -ftype get(int x, int idx = 1, int l = 0, int r = maxn) +// get minimum in some line x; +ll query(int x, int idx = 1, int l = 0, int r = maxx) { - int m = (l + r) / 2; - if(r - l == 1) { - return f(line[idx], x); - } else if(x < m) { - return min(f(line[idx], x), get(x, 2 * idx, l, m)); - } else { - return min(f(line[idx], x), get(x, 2 * idx + 1, m, r)); - } + ll cur = segs[idx].y(x); + if(l == r) + return cur; + int mid = (l + r) >> 1; + if (x <= mid) + return min(cur, query(x, idx * 2, l, mid)); + else + return min(cur, query(x, idx * 2 + 1, mid + 1, r)); +} + +// if the line slope is non-increasing. and query(x) is increasing. +// dp[i] = min{s[i] * f[j] + dp[j], for all j < i}. f[i] is non-increasing. s[i] increasing. +ll inters(line l1,line l2){ + return (l2.b-l1.b)/(l1.m-l2.m); +} +bool check(line l1,line l2,line l3){ + ll l12=inters(l1,l2); + ll l23=inters(l2,l3); + return l23> n >> k; + for(int i=1;i<=n;i++) cin >> s[i]; + for(int i=1;i<=n;i++) cin >> f[i]; + + deque q; + q.push_front({k,0}); + + for(int i=1;i<=n;i++){ + int x=s[i]; + while(q.size()>=2 && q[0].y(x)>q[1].y(x)) q.pop_front(); + dp[i]=q.front().y(x); + line now={f[i],dp[i]}; + + if(q.back().a==now.a) continue; + while(q.size()>=2 && check(q[q.size()-2],q[q.size()-1],now)) q.pop_back(); + q.push_back(now); + } + cout << dp[n] << '\n'; +} \ No newline at end of file diff --git a/data_structure/pbds.cpp b/data_structure/pbds.cpp index 72a7daa..80443c8 100644 --- a/data_structure/pbds.cpp +++ b/data_structure/pbds.cpp @@ -36,7 +36,6 @@ rb_tree_tag, tree_order_statistics_node_update> ; using order_map= tree, rb_tree_tag, tree_order_statistics_node_update>; - void test(){ int x; @@ -72,4 +71,9 @@ void test(){ cout<data = max(a->data, b->data); + if (l == r) return p; + int m = l + r >> 1; + p->lc = merge(a->lc, b->lc, l, m); + p->rc = merge(a->rc, b->rc, m + 1, r); + return p; + } + node *build(int l, int r, int x) { + node *p = new node; + if (l == r) return p->data = num[x][l], p; + int m = l + r >> 1; + p->lc = build(l, m, x), p->rc = build(m + 1, r, x); + p->data = max(p->lc->data, p->rc->data); + return p; + } + int query(int L, int R, int l, int r, node *p) { + if (L <= l && R >= r) return p->data; + int m = l + r >> 1, re = 0; + if (L <= m) re = query(L, R, l, m, p->lc); + if (R > m) + re = max(re, query(L, R, m + 1, r, p->rc)); + return re; + } +}; +struct seg_1D { + struct node { + seg_2D data; + node *lc, *rc; + } * root; + node *s_build(int l, int r) { + node *p = new node; + if (l == r) + return p->data.root = p->data.build(1, M, l), p; + int m = l + r >> 1; + p->lc = s_build(l, m), p->rc = s_build(m + 1, r); + p->data.root = p->data.merge( + p->lc->data.root, p->rc->data.root, 1, M); + return p; + } + int s_query(int L, int R, int l, int r, node *p, + int yl, int yr) { + if (L <= l && R >= r) + return p->data.query(yl, yr, 1, M, p->data.root); + int m = l + r >> 1, re = 0; + if (L <= m) + re = s_query(L, R, l, m, p->lc, yl, yr); + if (R > m) + re = max( + re, s_query(L, R, m + 1, r, p->rc, yl, yr)); + return re; + } + void init() { root = s_build(1, N); } + int query(int xl, int xr, int yl, int yr) { + return s_query(xl, xr, 1, N, root, yl, yr); + } +}; \ No newline at end of file diff --git a/geometry/CDQ.cpp b/geometry/CDQ.cpp new file mode 100644 index 0000000..9437983 --- /dev/null +++ b/geometry/CDQ.cpp @@ -0,0 +1,54 @@ +// for each j store number of pair (i, j) such that Xi <= Xj and Yi <= Yj and Zi <= Zj +struct point{ + int x, y, z, idx; + point(){x = y = z = 0;} + point(int a, int b, int c, int id):x(a), y(b), z(c), idx(id){} + bool operator==(const point &a){ + return x == a.x && y == a.y && z == a.z; + } +}; +const int maxn = 100001; +vec pts; +point staticArr[maxn]; +int ans[maxn], mt[maxn]; // mt is an binary index tree + +void cdq(int l, int r){ + if(l == r) + return ; + int mid = (l + r) >> 1; + cdq(l, mid); + cdq(mid + 1, r); + + vec arr; + for(int i = l ;i <= r; i++) + arr.eb(pts[i].z); + sort(al(arr)); arr.resize(unique(al(arr)) - arr.begin()); + fill(mt, mt + arr.size()+1, 0); + + int cpidx = 0, lid = l, rid = mid + 1; + for(rid = mid+1; rid <= r; rid++){ + while(lid <= mid && pts[lid].y <= pts[rid].y){ + add(upper_bound(al(arr), pts[lid].z) - arr.begin(), 1); + staticArr[cpidx++] = pts[lid]; + lid++; + } + ans[pts[rid].idx] += query(upper_bound(al(arr), pts[rid].z) - arr.begin()); + staticArr[cpidx++] = pts[rid]; + } + while(lid <= mid) staticArr[cpidx++] = pts[lid++]; + for(int i = l; i <= r; i++) pts[i] = staticArr[ i - l ]; +} +int main(){ + int n, idx = 0; cin >> n; fill(ans, ans+n, 0); pts.resize(n); + for(point& e: pts) + cin >> e.x >> e.y >> e.z; e.idx = idx++; + auto cmp_1 = [](point&a , point &b){ return a.x == b.x ? (a.y == b.y ? a.z < b.z : a.y < b.y ): a.x < b.x; }; + sort(al(pts), cmp_1); + for(int i = n-2; i >= 0 ; i--){ + if(pts[i] == pts[i+1]){ + ans[pts[i].idx] = ans[pts[i+1].idx] + 1; +// calculate ans that (pts[i] == pts[j] && i > j) as for ans (pts[i] == pts[j] && i < j) will be calculate in normal process + } + } + cdq(0, n-1); +} \ No newline at end of file diff --git a/geometry/slicing.cpp b/geometry/slicing.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/graph/Flow/Dinic_algorithm.cpp b/graph/Flow/Dinic_algorithm.cpp index 02daae6..5ee9971 100644 --- a/graph/Flow/Dinic_algorithm.cpp +++ b/graph/Flow/Dinic_algorithm.cpp @@ -1,84 +1,121 @@ -// O(V^2E) O(VE) finding argument path -// if unit capacity network then O(min(V^(2/3), E^1/2) E) -// solving bipartite matching O(E sqrt(V)) better than konig and flow(EV) +/* O(V^2E) O(VE) finding argument path +if unit capacity network then O(min(V^(2/3), E^1/2) E) +solving bipartite matching O(E sqrt(V)) better than konig and flow(EV) +------------------------------------------------------- +(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. +-------------------------------------------------------*/ +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; + }; -struct FlowEdge { - int u, v; - long long cap, flow = 0; - FlowEdge(int u, int v, long long cap) : u(u), v(v), cap(cap) {} -}; + int n, m, s, t, d[MAXN], cur[MAXN]; + vector edges; + vector G[MAXN]; -struct Dinic { - const long long flow_inf = 1e18; - vector edges; - vector> adj; - int n, m = 0; - int s, t; - vector level, ptr; - queue q; + void init(){ + edges.clear(); + for ( int i = 0 ; i < n ; i++ ) G[i].clear(); + n = 0; + } - Dinic(int n, int s, int t) : n(n), s(s), t(t) { - adj.resize(n); - level.resize(n); - ptr.resize(n); + // 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 - void add_edge(int u, int v, long long cap) { - edges.emplace_back(u, v, cap); - edges.emplace_back(v, u, 0); - adj[u].push_back(m); - adj[v].push_back(m + 1); - m += 2; + int add_node(){ + return n++; } - bool bfs() { - while (!q.empty()) { - int u = q.front(); - q.pop(); - for (int id : adj[u]) { - if (edges[id].cap - edges[id].flow < 1) continue; - if (level[edges[id].v] != -1) continue; - level[edges[id].v] = level[u] + 1; - q.push(edges[id].v); + 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 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 level[t] != -1; + return d[t] >= 0; } - long long dfs(int u, long long pushed) { - if (pushed == 0) return 0; - if (u == t) return pushed; - - for (int& cid = ptr[u]; cid < (int)adj[u].size(); cid++) { - int id = adj[u][cid]; - int v = edges[id].v; - if (level[u] + 1 != level[v] || edges[id].cap - edges[id].flow < 1) - continue; - - long long tr = dfs(v, min(pushed, edges[id].cap - edges[id].flow)); - - if (tr == 0) continue; - edges[id].flow += tr; - edges[id ^ 1].flow -= tr; - return tr; + 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; + } } - - level[u] = -1; - return 0; + return flow; } - long long flow() { - long long f = 0; - while (true) { - fill(level.begin(), level.end(), -1); - level[s] = 0; - q.push(s); - if (!bfs()) break; - fill(ptr.begin(), ptr.end(), 0); - while (long long pushed = dfs(s, flow_inf)) { - f += pushed; - } + 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 f; + return flow; } -}; \ No newline at end of file +} dinic; \ No newline at end of file diff --git a/graph/Flow/Edmonds-Karp-adjmax.cpp b/graph/Flow/Edmonds-Karp-adjmax.cpp deleted file mode 100644 index 479043f..0000000 --- a/graph/Flow/Edmonds-Karp-adjmax.cpp +++ /dev/null @@ -1,57 +0,0 @@ -// O((V+E)VE) ,簡單寫成 O(VE²) -#include -#include -using namespace std; -#define maxn 100 -typedef int Graph[MAXN][MAXN]; // adjacency matrix -Graph C, F, R; // 容量上限、流量、剩餘容量 -bool visit[MAXN]; // BFS經過的點 -int path[MAXN]; // BFS tree -int flow[MAXN]; // 源點到各點的流量瓶頸 - -int BFS(int s, int t) // 源點與匯點 -{ - memset(visit, false, sizeof(visit)); - - queue Q; // BFS queue - visit[s] = true; - path[s] = s; - flow[s] = 1e9; - Q.push(s); - - while (!Q.empty()) - { - int i = Q.front(); Q.pop(); - for (int j=0; j<100; ++j) - // 剩餘網路找擴充路徑 - if (!visit[j] && R[i][j] > 0) - { - visit[j] = true; - path[j] = i; - // 一邊找最短路徑,一邊計算流量瓶頸。 - flow[j] = min(flow[i], R[i][j]); - Q.push(j); - - if (j == t) return flow[t]; - } - } - return 0; // 找不到擴充路徑了,流量為零。 -} - -int Edmonds_Karp(int s, int t) -{ - memset(F, 0, sizeof(F)); - memcpy(R, C, sizeof(C)); - - int f, df; // 最大流的流量、擴充路徑的流量 - for (f=0; df=BFS(s, t); f+=df) - // 更新擴充路徑上每一條邊的流量 - for (int i=path[t], j=t; i!=j; i=path[j=i]) - { - F[i][j] = F[i][j] + df; - F[j][i] = -F[i][j]; - R[i][j] = C[i][j] - F[i][j]; - R[j][i] = C[j][i] - F[j][i]; - } - return f; -} \ No newline at end of file diff --git a/graph/Flow/Edmonds_Karp_2.cpp b/graph/Flow/Edmonds_Karp_2.cpp index 9a5f312..9f904e4 100644 --- a/graph/Flow/Edmonds_Karp_2.cpp +++ b/graph/Flow/Edmonds_Karp_2.cpp @@ -1,4 +1,4 @@ -#include +// O((V+E)VE) ,簡單寫成 O(VE²) struct Edge{ int from, to, cap, flow; Edge(int u, int v, int c, int f):from(u), to(v), cap(c), flow(f){} diff --git a/graph/Flow/MinCostMaxFlow-cp.cpp b/graph/Flow/MinCostMaxFlow-cp.cpp index 627447e..e722863 100644 --- a/graph/Flow/MinCostMaxFlow-cp.cpp +++ b/graph/Flow/MinCostMaxFlow-cp.cpp @@ -1,4 +1,4 @@ -struct CostFlow { +struct CostFlow { // Belmen-Ford O(V^2E^2) static const int MAXN = 350; const ll INF = 1ll<<60; diff --git a/graph/Flow/MinCostMaxFlow.cpp b/graph/Flow/MinCostMaxFlow.cpp deleted file mode 100644 index 81bed70..0000000 --- a/graph/Flow/MinCostMaxFlow.cpp +++ /dev/null @@ -1,91 +0,0 @@ -// by jinkela -template -struct MCMF -{ - static const int MAXN = 440; - static const TP INF = 999999999; - struct edge - { - int v, pre; - TP r, cost; - edge(int v, int pre, TP r, TP cost) : v(v), pre(pre), r(r), cost(cost) {} - }; - int n, S, T; - TP dis[MAXN], PIS, ans; - bool vis[MAXN]; - vector e; - int g[MAXN]; - void init(int _n) - { - memset(g, -1, sizeof(int) * ((n = _n) + 1)); - e.clear(); - } - void add_edge(int u, int v, TP r, TP cost, bool directed = false) - { - e.push_back(edge(v, g[u], r, cost)); - g[u] = e.size() - 1; - e.( - edge(u, g[v], directed ? 0 : r, -cost)); - g[v] = e.size() - 1; - } - TP augment(int u, TP CF) - { - if (u == T || !CF) - return ans += PIS * CF, CF; - vis[u] = 1; - TP r = CF, d; - for (int i = g[u]; ~i; i = e[i].pre) - { - if (e[i].r && !e[i].cost && !vis[e[i].v]) - { - d = augment(e[i].v, min(r, e[i].r)); - e[i].r -= d; - e[i ^ 1].r += d; - if (!(r -= d)) - break; - } - } - return CF - r; - } - bool modlabel() - { - for (int u = 0; u <= n; ++u) - dis[u] = INF; - static deque q; - dis[T] = 0, q.push_back(T); - while (q.size()) - { - int u = q.front(); - q.pop_front(); - TP dt; - for (int i = g[u]; ~i; i = e[i].pre) - { - if (e[i ^ 1].r && (dt = dis[u] - e[i].cost) < dis[e[i].v]) - { - if ((dis[e[i].v] = dt) <= dis[q.size() ? q.front() : S]) - { - q.push_front(e[i].v); - } - else - q.push_back(e[i].v); - } - } - } - for (int u = 0; u <= n; ++u) - for (int i = g[u]; ~i; i = e[i].pre) - e[i].cost += dis[e[i].v] - dis[u]; - return PIS += dis[S], dis[S] < INF; - } - TP mincost(int s, int t) - { - S = s, T = t; - PIS = ans = 0; - while (modlabel()) - { - do - memset(vis, 0, sizeof(bool) * (n + 1)); - while (augment(S, INF)); - } - return ans; - } -}; diff --git a/graph/Flow/Push_Relabel.cpp b/graph/Flow/Push_Relabel.cpp new file mode 100644 index 0000000..41da721 --- /dev/null +++ b/graph/Flow/Push_Relabel.cpp @@ -0,0 +1,74 @@ +// O(V^3) +const int inf = 1000000000; + +int n; +vector> capacity, flow; +vector height, excess; + +void push(int u, int v) +{ + int d = min(excess[u], capacity[u][v] - flow[u][v]); + flow[u][v] += d; + flow[v][u] -= d; + excess[u] -= d; + excess[v] += d; +} + +void relabel(int u) +{ + int d = inf; + for (int i = 0; i < n; i++) { + if (capacity[u][i] - flow[u][i] > 0) + d = min(d, height[i]); + } + if (d < inf) + height[u] = d + 1; +} + +vector find_max_height_vertices(int s, int t) { + vector max_height; + for (int i = 0; i < n; i++) { + if (i != s && i != t && excess[i] > 0) { + if (!max_height.empty() && height[i] > height[max_height[0]]) + max_height.clear(); + if (max_height.empty() || height[i] == height[max_height[0]]) + max_height.push_back(i); + } + } + return max_height; +} + +int max_flow(int s, int t) +{ + height.assign(n, 0); + height[s] = n; + flow.assign(n, vector(n, 0)); + excess.assign(n, 0); + excess[s] = inf; + for (int i = 0; i < n; i++) { + if (i != s) + push(s, i); + } + + vector current; + while (!(current = find_max_height_vertices(s, t)).empty()) { + for (int i : current) { + bool pushed = false; + for (int j = 0; j < n && excess[i]; j++) { + if (capacity[i][j] - flow[i][j] > 0 && height[i] == height[j] + 1) { + push(i, j); + pushed = true; + } + } + if (!pushed) { + relabel(i); + break; + } + } + } + + int max_flow = 0; + for (int i = 0; i < n; i++) + max_flow += flow[i][t]; + return max_flow; +} diff --git a/graph/Matching/blossom_matching.cpp b/graph/Matching/blossom_matching.cpp index 032a9ff..660a17d 100644 --- a/graph/Matching/blossom_matching.cpp +++ b/graph/Matching/blossom_matching.cpp @@ -1,6 +1,4 @@ -// by jinkela -// 最大圖匹配 -// O(V²(V+E)) +// by jinkela 最大圖匹配 O(V²(V+E)) #define MAXN 505 int n; //1-base vector g[MAXN]; diff --git a/graph/Shortest_Path/SingleSource.cpp b/graph/Shortest_Path/SingleSource.cpp new file mode 100644 index 0000000..c3d0a2a --- /dev/null +++ b/graph/Shortest_Path/SingleSource.cpp @@ -0,0 +1,49 @@ +// Bellman-Ford +vector> edges; +vector dis; +const int inf = 0x3f3f3f3f; +// return true if contain cycles +bool Bellman_Ford(int src) +{ + int V, E = edges.size(); + dis.resize(V, inf); dis[src] = 0; + for (int i = 0; i < V - 1; i++) + { + for (int j = 0; j < E; j++){ + int u, v, w; + tie(u, v, w) = edges[j]; + if(dis[u] != inf && dis[u] + w < dis[v]){ + dis[v] = dis[u] + w; + } + } + } + for (int j = 0; j < E; j++){ + int u, v, w; + tie(u, v, w) = edges[j]; + if(dis[u] != inf && dis[u] + w < dis[v]){ + return true; + } + } + return false; +} + +// dijkstra +vec>> Graph; // (w, v) +vec dis; // distance result +void dijkstra(int u) { + priority_queue, vec>, greater>> pq; + dis[u] = 0; + pq.emplace(0, u); + while(pq.size()){ + auto cur = pq.top(); + pq.pop(); + if(cur.first != dis[cur.second]) + continue; + for (auto it: Graph[cur.second]){ + if (cur.first + it.first < dis[it.second]){ + dis[it.second] = cur.first + it.first; + pq.emplace(dis[it.second], it.second); + } + } + } +} \ No newline at end of file diff --git a/graph/Shortest_Path/bellman-ford.cpp b/graph/Shortest_Path/bellman-ford.cpp deleted file mode 100644 index a814a9e..0000000 --- a/graph/Shortest_Path/bellman-ford.cpp +++ /dev/null @@ -1,29 +0,0 @@ -vector> edges; -vector dis; -const int inf = 0x3f3f3f3f; -// return true if contain cycles -bool Bellman_Ford(int src) -{ - int V; // # of vertices - int E = edges.size(); - dis.resize(V, inf); - dis[src] = 0; - for (int i = 0; i < V - 1; i++) - { - for (int j = 0; j < E; j++){ - int u, v, w; - tie(u, v, w) = edges[j]; - if(dis[u] != inf && dis[u] + w < dis[v]){ - dis[v] = dis[u] + w; - } - } - } - for (int j = 0; j < E; j++){ - int u, v, w; - tie(u, v, w) = edges[j]; - if(dis[u] != inf && dis[u] + w < dis[v]){ - return true; - } - } - return false; -} \ No newline at end of file diff --git a/graph/Shortest_Path/dijkstra.cpp b/graph/Shortest_Path/dijkstra.cpp deleted file mode 100644 index 596a283..0000000 --- a/graph/Shortest_Path/dijkstra.cpp +++ /dev/null @@ -1,24 +0,0 @@ -vec>> Graph; // (w, v) - -vec dis; // distance result -void dijkstra(int u) { - priority_queue, vec>, greater>> pq; - - dis[u] = 0; - pq.emplace(0, u); - - while(pq.size()){ - auto cur = pq.top(); - pq.pop(); - - if(cur.first != dis[cur.second]) - continue; - - for (auto it: Graph[cur.second]){ - if (cur.first + it.first < dis[it.second]){ - dis[it.second] = cur.first + it.first; - pq.emplace(dis[it.second], it.second); - } - } - } -} \ No newline at end of file diff --git a/graph/Tree/backpack_onTree.cpp b/graph/Tree/backpack_onTree.cpp index da909e2..421f228 100644 --- a/graph/Tree/backpack_onTree.cpp +++ b/graph/Tree/backpack_onTree.cpp @@ -1,6 +1,4 @@ -// 樹上依賴背包問題 -// 上下界優化 Time complexity = O(NM) -// 另有Postorder 的順序做DP也能做到O(NM) +// 樹上依賴背包問題的上下界優化 Time complexity = O(NM),另有Postorder 的順序做DP也能做到O(NM) void dfs(int u) { siz[u]=1; diff --git a/graph/graph_Theories.tex b/graph/graph_Theories.tex index 1ac0e35..2996968 100644 --- a/graph/graph_Theories.tex +++ b/graph/graph_Theories.tex @@ -12,14 +12,28 @@ \subsubsection{Konig's Theorem} In any bipartite graph, the number of edges in a maximum matching equals the number of vertices in a minimum vertex cover. +\subsubsection{Constructing Minimum Cover} + +二分圖左邊為 X集合 右邊為 Y集合,S和T分別代表從X的unmatch點開始,可以透過alternating path走到、各自屬於 X 和 Y 的點。$S\subseteq X, T\subseteq Y$ +則 min cover = $T \cup \left(X-S\right)$ + \subsubsection{Independent Set on Bipartite graph} -In any bipartite graph, the complement of mimimum vertex cover is a maximum Independent set. +In any bipartite graph, the complement of minimum vertex cover is a maximum Independent set. \subsubsection{Minimum Weighted Vertex Cover} 二分圖的minimum weighted vertex cover可以透過最大流求出,建模方式如下:source 連向所有左邊的點,capacity是點權,所有右邊的點連向sink,capacity是點權,對於二分圖中原本有的邊,從左邊連向右邊,capacity為INF。可以透過此圖的 min cut構造出 vertex cover,而min cut可以透過此圖的 max flow 求出。 +In bipartite graph, minimum weighted vertex cover = maximum weighted bipartite matching M. + +\subsubsection{Hall's condition} + +令左邊的點集合為$X$,右邊的點集合為$Y$,$|X| = |Y| = n$ +If $|N(S)| \geq |S|$ for all $S \subseteq X$, then exist $n$ matching(perfect matching). +$N(S)$代表S的neighbor set + + \subsubsection{Biconnected Component} If a Biconnected component is 2-connected \begin{enumerate} diff --git a/number_theory/BigInteger2.cpp b/number_theory/BigInteger.cpp similarity index 100% rename from number_theory/BigInteger2.cpp rename to number_theory/BigInteger.cpp diff --git a/number_theory/Biginteger.cpp b/number_theory/Biginteger.cpp deleted file mode 100644 index 6de38ec..0000000 --- a/number_theory/Biginteger.cpp +++ /dev/null @@ -1,108 +0,0 @@ -struct BigInteger { - static const int BASE = 100000000; - static const int WIDTH = 8; - vec s; - - BigInteger(long long num = 0) { *this = num; } - BigInteger operator = (long long num) { - s.clear(); - do{ - s.push_back(num % BASE); - num /= BASE; - } while (num > 0); - return *this; - } - - BigInteger operator = (const string& str){ - s.clear(); - int x, len = (str.length() - 1) / WIDTH + 1; - for (int i = 0; i < len;i++){ - int end = str.length() - i * WIDTH; - int start = max(0, end - WIDTH); - sscanf(str.substr(start, end - start).c_str(), "%d", &x); - s.push_back(x); - } - return *this; - } - - BigInteger operator+ (const BigInteger b) const{ - BigInteger c; - c.s.clear(); - for(int i=0,g=0;;i++){ - if(g== 0 && i >=s.size() && i >=b.s.size()) - break; - int x = g; - if(i= BASE){ - if(i + 1 < c.s.size()){ - c.s.push_back(c.s[i] / BASE); - }else{ - c.s[i + 1] += c.s[i] / BASE; - } - c.s[i] %= BASE; - } - } - return c; - } - - bool operator< (const BigInteger& b) const{ - if(s.size() != b.s.size()) return s.size() < b.s.size(); - for(int i=s.size() -1 ; i>=0;i--) - if(s[i] != b.s[i]) return s[i] < b.s[i]; - return false; // Equal - } - - bool operator> (const BigInteger& b) const{return b < *this;} - bool operator<= (const BigInteger& b) const {return !(b<*this);} - bool operator>=(const BigInteger& b) const {return !(*this < b);} - bool operator!=(const BigInteger& b) const {return b< *this || *this < b;} - bool operator==(const BigInteger& b)const {return !(b<*this) && !(*this= 0;i--){ - char buf[20]; - sprintf(buf,"%08d",x.s[i]); - for(int j = 0;j> (istream &in, BigInteger & x){ - string s; - if(!(in >> s)) return in; - x= s; - return in; -} \ No newline at end of file