[ Letter Song - 初音Miku (Author: dokiyo) ]
机房挂上了高级电子牌子,说是离 NOIp 还有 49 天。
挺红挺亮的,也很扎眼,一抬头就看得见,和自己算的日子差不多,但是想一想,还是比自己感觉到的还更近一些。
搞得自己越来越虚。
越临近考试反而状态越差了的感觉,考试也是随随便便就被别人吊打,做不动题也打不起精神。
很难想象这样的自己要是真的没拿到奖会变成什么样子,几个星期前信誓旦旦要拿一等奖的热血倒是已经凉了一半了。
看着两年多前办的一中饭卡,卡面已经昏黄布满一些细碎的划痕,还有两年多前贴上的卡贴,有种怅然若失的感觉呢。
背离过,也尝试寻找过拾起过,所谓初心的东西。
就顺手整理一些还不太会的模板以便复习吧,有些也比较远古了,可能比较丑,不过应该不影响食用……如果以后写相关的博客,大概也会在这里挂一下的。
1. KMP算法
1 #include <cstdio> 2 #include <cctype> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 7 const int maxl = 1000000 + 10; 8 char a[maxl], b[maxl]; 9 int ans[maxl], nxt[maxl], lena, lenb; 10 11 int main(int argc, char const *argv[]) 12 { 13 scanf("%s%s", a, b); 14 lena = strlen(a), lenb = strlen(b); 15 int t = 0; nxt[0] = 0; 16 for(int i = 1; i < lenb; ++i) { 17 while( t && b[i] != b[t] ) t = nxt[t - 1]; 18 if( b[i] == b[t] ) ++t; nxt[i] = t; 19 } 20 int k = 0; t = 0; 21 for(int i = 0; i < lena; ++i) { 22 while( t && a[i] != b[t] ) t = nxt[t - 1]; 23 if( a[i] == b[t] ) ++t; 24 if( t == lenb ) ans[++k] = i - lenb + 2; 25 } 26 for(int i = 1; i <= k; ++i) printf("%d ", ans[i]); 27 for(int i = 0; i < lenb; ++i) printf("%d ", nxt[i]); 28 return 0; 29 }
2. Manacher算法
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 const int maxn = 11000000 + 10; 7 char tmp[maxn], s[maxn << 1]; 8 int l, p[maxn << 1]; 9 10 inline int Manacher() { 11 int ans = 0, pos = 0; 12 for(int i = 0; i <= l; ++i) { 13 if( pos + p[pos] > i ) p[i] = min(p[2 * pos - i], pos + p[pos] - i); 14 while( i - p[i] >= 0 && i + p[i] <= l && s[i - p[i]] == s[i + p[i]] ) 15 ++p[i]; 16 if( pos + p[pos] < i + p[i] ) pos = i; 17 ans = max(ans, p[i]); 18 } 19 return ans - 1; 20 } 21 22 int main(int argc, char const *argv[]) 23 { 24 scanf("%s", tmp); 25 int len = strlen(tmp); l = -1; 26 for(int i = 0; i < len; ++i) 27 s[++l] = '#', s[++l] = tmp[i]; 28 s[++l] = '#'; 29 printf("%d ", Manacher()); 30 31 return 0; 32 }
3. AC自动机(丑死了)
1 // Warning: There Is An Error In This Code. 2 // When There Are Two Strings That One Is Included By The Other. 3 // It Will Give A Wrong Answer. 4 // By. Kimitsu Nanjo In 06.28.2018. 5 // https://www.luogu.org/problemnew/show/P3796 6 7 #include <cstdio> 8 #include <cstdlib> 9 #include <cstring> 10 #include <algorithm> 11 12 const int maxn = 1000000 + 10; 13 char a[maxn], word[maxn]; 14 15 struct Node{ 16 int cnt; 17 Node *fail, *next[26]; 18 }*queue[maxn], *root; 19 20 inline void Refl(Node *root) { 21 root->cnt = 0; 22 root->fail = NULL; 23 for(int i = 0; i < 26; ++i) 24 root->next[i] = NULL; 25 } 26 27 inline void Insert(char *s, int len) { 28 Node *p = root; 29 for(int i = 0; i < len; ++i) { 30 if( p->next[s[i] - 'a'] == NULL ) { 31 Node *q = (Node*)malloc(sizeof(Node)); Refl(q); 32 p->next[s[i] - 'a'] = q; 33 } 34 p = p->next[s[i] - 'a']; 35 } 36 p->cnt++; 37 } 38 39 inline void Build_fail(Node *root) { 40 int head = 0, tail = 0; //队列头、尾指针 41 queue[head++] = root; //先将root入队 42 while( head != tail ) 43 { 44 Node *p = NULL, *temp = queue[tail++]; //弹出队头结点 45 for(int i = 0; i < 26; ++i) { 46 if( temp->next[i] != NULL ) { 47 //找到实际存在的字符结点 48 //temp->next[i] 为该结点,temp为其父结点 49 if( temp == root ) temp->next[i]->fail = root; 50 //若是第一层中的字符结点,则把该结点的失败指针指向root 51 else { 52 //依次回溯该节点的父节点的失败指针直到某节点的next[i]与该节点相同 53 //则把该节点的失败指针指向该next[i]节点; 54 //若回溯到 root 都没有找到,则该节点的失败指针指向 root 55 p = temp->fail; //将该结点的父结点的失败指针给p 56 while( p != NULL ) { 57 if( p->next[i] != NULL ) { 58 temp->next[i]->fail = p->next[i]; 59 break; 60 } 61 p = p->fail; 62 } 63 //让该结点的失败指针也指向root 64 if( p == NULL ) temp->next[i]->fail = root; 65 } 66 queue[head++] = temp->next[i]; 67 //每处理一个结点,都让该结点的所有孩子依次入队 68 } 69 } 70 } 71 } 72 73 inline int Querry(Node *root, int len) { //i为主串指针,p为模式串指针 74 int ans = 0; 75 Node *p = root; 76 for(int i = 0; i < len; ++i) { 77 //由失败指针回溯查找,判断s[i]是否存在于Trie树中 78 while( p->next[a[i] - 'a'] == NULL && p != root ) p = p->fail; 79 p = p->next[a[i] - 'a']; //找到后p指针指向该结点 80 if( p == NULL ) p = root; //若指针返回为空,则没有找到与之匹配的字符 81 Node *temp = p; //匹配该结点后,沿其失败指针回溯,判断其它结点是否匹配 82 while( temp != root ) { //匹配结束控制 83 if( temp->cnt >= 0 ) //判断该结点是否被访问 84 ans += temp->cnt, temp->cnt = -1; 85 //由于cnt初始化为 0,所以只有cnt>0时才统计了单词的个数, 标记已访问过 86 temp = temp->fail; //回溯 失败指针 继续寻找下一个满足条件的结点 87 } 88 } 89 return ans; 90 } 91 92 void Free_Node(Node *p) { 93 for(int i = 0; i < 26; ++i) 94 if( p->next[i] != NULL ) Free_Node(p->next[i]); 95 free(p); 96 } 97 98 int main(int argc, char* const argv[]) 99 { 100 int n = 0; 101 root = (struct Node*)malloc(sizeof(Node)), Refl(root); 102 scanf("%d", &n); 103 for(int i = 1; i <= n; ++i) { 104 scanf("%s", word); 105 Insert(word, strlen(word)); 106 } 107 Build_fail(root); 108 scanf("%s", a); 109 printf("%d ", Querry(root, strlen(a))); 110 111 return 0; 112 }
4. 求欧拉函数
1 #include <cctype> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 #include <algorithm> 6 using namespace std; 7 8 typedef long long u64; 9 const int maxn = 10000000 + 10; 10 int n, prime[maxn], not_pri[maxn], phi[maxn]; 11 12 /* 单个欧拉函数 */ 13 inline u64 Sig_Phi(u64 x) { 14 u64 phi = x; 15 for(u64 i = 2; i * i <= x; ++i) { 16 if( !(x % i) ) { 17 phi = phi - phi / i; 18 while( !(x % i) ) x /= i; 19 } 20 } 21 if( x > 1 ) phi = phi - phi / x; 22 return phi; 23 } 24 25 /* 线性求欧拉函数 */ 26 inline void Che_Phi(u64 x) { 27 phi[1] = 1; 28 for(int i = 2; i < x; ++i) phi[i] = i; 29 for(int i = 2; i < x; ++i) { 30 if( phi[i] == i ) for(int j = i; j < x; j += i) 31 phi[j] = phi[j] / i * (i - 1); 32 } 33 } 34 35 /* 线性求欧拉函数 */ 36 inline void Get_Phi(u64 x) { 37 int p = -1, k; 38 phi[1] = 1, not_pri[0] = not_pri[1] = 1; 39 for(int i = 2; i <= x; ++i) { 40 if( !not_pri[i] ) { 41 prime[++p] = not_pri[i] = i; 42 phi[i] = i - 1; 43 } 44 for(int j = 0; j <= p; ++j) { 45 if( (k = prime[j] * i) > x ) break; 46 not_pri[k] = prime[j]; 47 if( not_pri[i] == prime[j] ) { 48 phi[k] = phi[i] * prime[j]; break; 49 } else phi[k] = phi[i] * (prime[j] - 1); 50 } 51 } 52 } 53 54 int main(int argc, char* const argv[]) 55 { 56 Get_Phi(10000000); 57 for(int i = 1; i <= 20; ++i) printf("%d ", phi[i]); 58 // while( ~scanf("%lld", &n) ) printf("%lld ", Phi(n)); 59 60 return 0; 61 }
5. 中国剩余定理(含拓欧)
1 #include <cctype> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 #include <algorithm> 6 using namespace std; 7 8 typedef long long int u64; 9 10 u64 Ex_gcd(u64 a, u64 b, u64 &x, u64 &y) { 11 if( !b ) { x = 1, y = 0; return a; } 12 u64 d = Ex_gcd(b, a % b, x, y), tmp = x; 13 x = y, y = tmp - a / b * y; 14 return d; 15 } 16 17 u64 CRT(u64 *a, u64 *b, u64 k) { 18 u64 x = 0, y = 0, m = 0, mul = 1, ans = 0; 19 for(int i = 1; i <= k; ++i) mul *= a[i]; 20 for(int i = 1; i <= k; ++i) { 21 m = mul / a[i]; 22 Ex_gcd(m, a[i], x, y); 23 ans = (ans + m * x * b[i]) % mul; 24 } 25 return ans > 0 ? ans : ans + mul; 26 } 27 28 int main(int argc, char* const argv[]) 29 { 30 u64 n = 0, a[12] = {0}, b[12] = {0}; 31 scanf("%lld", &n); 32 for(int i = 1; i <= n; ++i) 33 scanf("%lld%lld", &a[i], &b[i]); 34 printf("%lld ", CRT(a, b, n)); 35 36 return 0; 37 }
6. ST表
1 /* 2 ST表是利用的是倍增的思想 3 拿最大值来说 4 我们用Max[i][j]表示,从i位置开始的2^j个数中的最大值, 5 例如Max[i][1]表示的是i位置和i+1位置中两个数的最大值. 6 查询的时候也比较简单,我们计算出log2(区间长度) 7 然后对于左端点和右端点分别进行查询,这样可以保证一定可以覆盖查询的区间 8 刚开始学的时候我不太理解为什么从右端点开始查的时候左端点是r−2k+1 9 实际很简单,因为我们需要找到一个点x,使得x+2k−1=r 10 这样的话就可以得到x=r−2k+1 11 */ 12 #include <cstdio> 13 #include <cctype> 14 #include <cstring> 15 #include <algorithm> 16 using namespace std; 17 18 const int maxn = 1e5 + 10; 19 const int maxm = 1e6 + 10; 20 int n, m, a[maxn][21], lg[maxn]; 21 22 inline void read(int &x) { 23 register char ch = 0; x = 0; 24 while( !isdigit(ch) ) ch = getchar(); 25 while( isdigit(ch) ) x = (x * 10) + (ch ^ 48), ch = getchar(); 26 } 27 28 int main() { 29 scanf("%d%d", &n, &m); 30 for(int i = 1; i <= n; ++i) read(a[i][0]); 31 for(int j = 1; j <= 20; ++j) 32 for(int i = 1; i + (1 << j) - 1 <= n; ++i) //注意这里要控制边界 33 a[i][j] = max(a[i][j - 1], a[i + (1 << (j - 1))][j - 1]); 34 int tmp = 3; 35 for(int i = 3; i <= n; ++i) { // 处理log2(i) 36 lg[i] = lg[i - 1]; 37 if( i == tmp ) ++lg[i], tmp = (tmp << 1) - 1; 38 } 39 int l, r, ans; 40 for(int i = 1; i <= m; ++i) { 41 read(l), read(r); 42 int t = lg [r - l + 1]; 43 ans = max(a[l][t], a[r - (1 << t) + 1][t]); //把拆出来的区间分别取最值 44 printf("%d ", ans); 45 } 46 return 0; 47 }
7. 割点
1 #include<cstdio> 2 #include<cctype> 3 #include<algorithm> 4 using namespace std; 5 6 const int neko = 200000 + 10; 7 int n, m, head[neko], stack[neko], t, p, top, dfn_num, col_num, edge_num; 8 int cut[neko], ans[neko], dfn[neko], low[neko], col[neko], cnt[neko]; 9 10 struct Edge { int u, v, nxt; } edge[neko << 1]; 11 12 inline int read() { 13 register char ch = 0; register int w = 0, x = 0; 14 while( !isdigit(ch) ) w |= (ch == '-'), ch = getchar(); 15 while( isdigit(ch) ) x = (x * 10) + (ch ^ 48), ch = getchar(); 16 return w ? -x : x; 17 } 18 19 void Tarjan(int s) { 20 int root = 0; 21 dfn[s] = low[s] = ++dfn_num, stack[++top] = s; 22 for(int i = head[s]; i; i = edge[i].nxt) { 23 if( !dfn[edge[i].v] ) { 24 Tarjan(edge[i].v), low[s] = min(low[s], low[edge[i].v]); 25 if ( low[edge[i].v] >= dfn[s] && s != p ) cut[s] = 1; 26 if ( s == p ) ++root; 27 } 28 low[s] = min(low[s], dfn[edge[i].v]); 29 if( s == p && root >= 2 ) cut[s] = 1; 30 } 31 } 32 33 int main() { 34 scanf("%d%d", &n, &m); 35 for(int x, y, i = 1; i <= m; ++i) { 36 x = read(), y = read(); 37 edge[++edge_num].u = x, edge[edge_num].v = y; 38 edge[edge_num].nxt = head[x], head[x] = edge_num; 39 edge[++edge_num].u = y, edge[edge_num].v = x; 40 edge[edge_num].nxt = head[y], head[y] = edge_num; 41 } 42 for(int i = 1; i <= n; ++i) if( !dfn[i] ) p = i, Tarjan(i); 43 for(int i = 1; i <= n; ++i) if( cut[i] ) ans[++t] = i; 44 printf("%d ", t); 45 for(int i = 1; i <= t; ++i) printf("%d ", ans[i]); 46 return 0; 47 }
8. 树链剖分
1 #include <queue> 2 #include <cctype> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 using namespace std; 7 8 #define lch (x << 1) 9 #define rch (x << 1) | 1 10 11 const int iinf = 2147483647; 12 const int maxn = 60000 + 10; 13 int n, head[maxn], value[maxn], dfn[maxn], idfn[maxn], dfn_num; 14 int top[maxn], size[maxn], son[maxn], pre[maxn], deep[maxn], edge_num; 15 16 struct Edge{ int v, nxt; }edge[maxn << 1]; 17 18 class Seg_tree{ 19 private: 20 int mas[maxn << 1] = {0}, sum[maxn << 1] = {0}; 21 public: 22 inline void Maintain(int x) { 23 sum[x] = sum[lch] + sum[rch]; 24 mas[x] = max(mas[lch], mas[rch]); 25 } 26 27 void Build(int x, int l, int r) { 28 if( l == r ) { sum[x] = mas[x] = value[idfn[l]]; return ; } 29 int mid = (l + r) >> 1; 30 Build(lch, l, mid), Build(rch, mid + 1, r); 31 Maintain(x); 32 } 33 34 void Update(int x, int l, int r, int ques, int num) { 35 if( l == r ) { sum[x] = mas[x] = num; return ; } 36 int mid = (l + r) >> 1; 37 if( ques <= mid ) Update(lch, l, mid, ques, num); 38 else Update(rch, mid + 1, r, ques, num); 39 Maintain(x); 40 } 41 42 int Querry_max(int x, int l, int r, int quesl, int quesr) { 43 if( l >= quesl && r <= quesr ) { return mas[x]; } 44 int mid = (l + r) >> 1, ans1 = -iinf, ans2 = -iinf; 45 if( quesl <= mid ) ans1 = Querry_max(lch, l, mid, quesl, quesr); 46 if( quesr > mid ) ans2 = Querry_max(rch, mid + 1, r, quesl, quesr); 47 return max(ans1, ans2); 48 } 49 50 int Querry_sum(int x, int l, int r, int quesl, int quesr) { 51 if( l >= quesl && r <= quesr ) { return sum[x]; } 52 int mid = (l + r) >> 1, ans = 0; 53 if( quesl <= mid ) ans += Querry_sum(lch, l, mid, quesl, quesr); 54 if( quesr > mid ) ans += Querry_sum(rch, mid + 1, r, quesl, quesr); 55 return ans; 56 } 57 }tree; 58 59 inline int read() { 60 register char ch = 0; register int w = 0, x = 0; 61 while( !isdigit(ch) ) w |= (ch == '-'), ch = getchar(); 62 while( isdigit(ch) ) x = (x * 10) + (ch ^ 48), ch = getchar(); 63 return w ? -x : x; 64 } 65 66 inline void Add_edge(int u, int v) { 67 edge[++edge_num].v = v; 68 edge[edge_num].nxt = head[u], head[u] = edge_num; 69 } 70 71 int Deepfs_1(int x) { 72 int tmp = 0; 73 for(int i = head[x]; i; i = edge[i].nxt) { 74 if( edge[i].v == pre[x] ) continue; 75 pre[edge[i].v] = x, deep[edge[i].v] = deep[x] + 1; 76 size[x] += Deepfs_1(edge[i].v); 77 if( tmp < size[edge[i].v] ) tmp = size[edge[i].v], son[x] = edge[i].v; 78 } 79 return head[x] ? ++size[x] : size[x] = 1; 80 } 81 82 void Deepfs_2(int x, int t) { 83 top[x] = t, dfn[x] = ++dfn_num, idfn[dfn_num] = x; 84 if( son[x] ) Deepfs_2(son[x], t); 85 for(int i = head[x]; i; i = edge[i].nxt) 86 if( edge[i].v != son[x] && edge[i].v != pre[x] ) 87 Deepfs_2(edge[i].v, edge[i].v); 88 } 89 90 inline int Querry_max(int x, int y) { 91 int ans = -iinf; 92 while( top[x] != top[y] ) { 93 if( deep[top[x]] >= deep[top[y]] ) { 94 ans = max(ans, tree.Querry_max(1, 1, n, dfn[top[x]], dfn[x])); 95 x = pre[top[x]]; 96 } else { 97 ans = max(ans, tree.Querry_max(1, 1, n, dfn[top[y]], dfn[y])); 98 y = pre[top[y]]; 99 } 100 } 101 if( dfn[x] > dfn[y] ) swap(x, y); 102 return max(ans, tree.Querry_max(1, 1, n, dfn[x], dfn[y])); 103 } 104 105 inline int Querry_sum(int x, int y) { 106 int ans = 0; 107 while( top[x] != top[y] ) { 108 if( deep[top[x]] >= deep[top[y]] ) { 109 ans += tree.Querry_sum(1, 1, n, dfn[top[x]], dfn[x]); 110 x = pre[top[x]]; 111 } else { 112 ans += tree.Querry_sum(1, 1, n, dfn[top[y]], dfn[y]); 113 y = pre[top[y]]; 114 } 115 } 116 if( dfn[x] > dfn[y] ) swap(x, y); 117 return ans + tree.Querry_sum(1, 1, n, dfn[x], dfn[y]); 118 } 119 120 int main(int argc, char* const argv[]) 121 { 122 scanf("%d", &n); 123 for(int i = 1; i < n; ++i) { 124 int u = read(), v = read(); 125 Add_edge(u, v), Add_edge(v, u); 126 } 127 for(int i = 1; i <= n; ++i) value[i] = read(); 128 size[1] = Deepfs_1(1), Deepfs_2(1, 1), tree.Build(1, 1, n); 129 130 int q = read(); char ques[10]; 131 for(int i = 1; i <= q; ++i) { 132 scanf("%s", ques); 133 int u = read(), v = read(); 134 switch( ques[1] ) { 135 case 'S': printf("%d ", Querry_sum(u, v)); break; 136 case 'M': printf("%d ", Querry_max(u, v)); break; 137 case 'H': tree.Update(1, 1, n, dfn[u], v); break; 138 } 139 } 140 141 return 0; 142 }
9. 可持久化线段树
1 #include <queue> 2 #include <cstdio> 3 #include <cctype> 4 #include <vector> 5 #include <cstring> 6 #include <iostream> 7 #include <algorithm> 8 using namespace std; 9 10 vector<int> id; 11 12 const int maxn = 2 * 100000 + 10; 13 int n, m, a[maxn], node_num; 14 15 struct Node { 16 int sum; 17 Node *lchild, *rchild; 18 19 Node() { sum = 0, lchild = rchild = NULL; } 20 ~Node() {}; 21 } node[25 * maxn], *root[maxn]; 22 23 class Segment_tree { 24 public: 25 void Build(Node *root, int l, int r) { 26 root->lchild = &node[++node_num], root->rchild = &node[++node_num]; 27 if( l == r ) return ; 28 int mid = (l + r) >> 1; 29 Build(root->lchild, l, mid), Build(root->rchild, mid + 1, r); 30 } 31 32 void Insert(Node *root, Node *&new_root, int l, int r, int pos) { 33 node[++node_num] = *root, new_root = &node[node_num], ++new_root->sum; 34 if( l == r ) return ; 35 int mid = (l + r) >> 1; 36 if( pos <= mid ) Insert(root->lchild, new_root->lchild, l, mid, pos); 37 else Insert(root->rchild, new_root->rchild, mid + 1, r, pos); 38 } 39 40 int Querry(Node *root_l, Node *root_r, int l, int r, int pos) { 41 if( l == r ) return l; 42 int mid = (l + r) >> 1, sum = root_r->lchild->sum - root_l->lchild->sum; 43 if( sum >= pos ) return Querry(root_l->lchild, root_r->lchild, l, mid, pos); 44 else return Querry(root_l->rchild, root_r->rchild, mid + 1, r, pos - sum); 45 } 46 } tree; 47 48 inline int read() { 49 register char ch = 0; register int w = 0, x = 0; 50 while( !isdigit(ch) ) w |= (ch == '-'), ch = getchar(); 51 while( isdigit(ch) ) x = (x * 10) + (ch ^ 48), ch = getchar(); 52 return w ? -x : x; 53 } 54 55 inline int Get_num(int x) { 56 return lower_bound(id.begin(), id.end(), x) - id.begin() + 1; 57 } 58 59 int main(int argc, char const *argv[]) 60 { 61 scanf("%d%d", &n, &m); 62 for(int i = 1; i <= n; ++i) a[i] = read(), id.push_back(a[i]); 63 sort(id.begin(), id.end()); 64 id.erase(unique(id.begin(), id.end()), id.end()); 65 root[0] = &node[0], tree.Build(root[0], 1, n); 66 for(int i = 1; i <= n; ++i) { 67 // printf("%s ", root[i - 1] == 0 ? "true" : "false"); 68 tree.Insert(root[i - 1], root[i], 1, n, Get_num(a[i])); 69 } 70 while( m-- ) { 71 int l = read(), r = read(), k = read(); 72 printf("%d ", id[tree.Querry(root[l - 1], root[r], 1, n, k) - 1]); 73 } 74 75 return 0; 76 }
10. 费用流
1 #include <queue> 2 #include <cctype> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 using namespace std; 7 8 typedef pair<int, int> pairs; 9 10 const int maxn = 5000 + 10; 11 const int maxm = 50000 + 10; 12 const int iinf = 0x3f3f3f3f; 13 int n, m, s, t, head[maxn], edge_num; 14 int dis[maxn], vis[maxn], pre[maxn], rec[maxn]; 15 16 struct Edge{ int v, f, c, nxt; }edge[maxm << 1]; 17 18 inline int read() { 19 register char ch = 0; register int x = 0; 20 while( !isdigit(ch) ) ch = getchar(); 21 while( isdigit(ch) ) x = (x * 10) + (ch ^ 48), ch = getchar(); 22 return x; 23 } 24 25 inline void Add_edge(int u, int v, int f, int c) { 26 edge[++edge_num].v = v, edge[edge_num].f = f, edge[edge_num].c = c; 27 edge[edge_num].nxt = head[u], head[u] = edge_num; 28 } 29 30 inline bool SPFA(int s, int t) { 31 queue<int> q; 32 memset(vis, 0, sizeof vis); 33 memset(dis, 0x3f, sizeof dis); 34 dis[s] = 0, vis[s] = 1, q.push(s); 35 while( !q.empty() ) { 36 int x = q.front(); q.pop(); 37 vis[x] = 0; 38 for(int i = head[x]; i; i = edge[i].nxt) 39 if( dis[edge[i].v] > dis[x] + edge[i].c && edge[i].f ) { 40 dis[edge[i].v] = dis[x] + edge[i].c; 41 pre[edge[i].v] = x, rec[edge[i].v] = i; 42 if( !vis[edge[i].v] ) vis[edge[i].v] = 1, q.push(edge[i].v); 43 } 44 } 45 if( dis[t] == iinf ) return false; 46 else return true; 47 } 48 49 inline pairs Edmond_Karp(int s, int t) { 50 int k, min_flow, min_cost = 0, max_flow = 0; 51 while( SPFA(s, t) ) { 52 k = t, min_flow = iinf; 53 while( k != s ) min_flow = min(min_flow, edge[rec[k]].f), k = pre[k]; 54 k = t, max_flow += min_flow; 55 while( k != s ) { 56 min_cost += min_flow * edge[rec[k]].c; 57 if( rec[k] & 1 ) { 58 edge[rec[k]].f -= min_flow, edge[rec[k] + 1].f += min_flow; 59 } else edge[rec[k]].f -= min_flow, edge[rec[k] - 1].f += min_flow; 60 k = pre[k]; 61 } 62 } 63 return make_pair(max_flow, min_cost); 64 } 65 66 int main(int argc, char* const argv[]) 67 { 68 freopen("nanjolno.in", "r", stdin); 69 freopen("nanjolno.out", "w", stdout); 70 71 scanf("%d%d%d%d", &n, &m, &s, &t); 72 for(int i = 1; i <= m; ++i) { 73 int u = read(), v = read(), f = read(), c = read(); 74 Add_edge(u, v, f, c), Add_edge(v, u, 0, -c); 75 } 76 pairs ans = Edmond_Karp(s, t); 77 printf("%d %d ", ans.first, ans.second); 78 79 fclose(stdin), fclose(stdout); 80 return 0; 81 }
考前持续更新(Before 2018.11.10),大概?
—— 并不需要什么理由,只是因为想做所以去做。 自己真正想做的事情,不就是这样开始的吗。