[模板] 一些要复习的模板
分类:
IT文章
•
2025-01-09 15:21:38
[ 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 }
2018.06.27
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 }
2018.06.27
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 }
2018.06.29
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 }
2018.09.19
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 }
2018.07.01
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 }
2018.05.03
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 }
2018.04.10
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 }
2018.07.08
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 }
2018.09.05
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 }
2018.07.05
考前持续更新(Before 2018.11.10),大概?
—— 并不需要什么理由,只是因为想做所以去做。 自己真正想做的事情,不就是这样开始的吗。