Skip to content

Commit 6d63af9

Browse files
committed
v1.0.5:增加了后缀数组和其他若干算法、修改了部分错误
1 parent 45807c8 commit 6d63af9

13 files changed

Lines changed: 2941 additions & 222 deletions

README.md

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
**当前最新普通版发布版本为 `v1.0.4`****最新打印版发布版本为 `v1.0.0` (总词数约7.7w(含代码))**
1+
**当前最新普通版发布版本为 `v1.0.5`****最新打印版发布版本为 `v1.0.0` (总词数约7.7w(含代码))**
22

33
成品为 `template.pdf` (移步 [releases](https://github.com/lr580/algorithm_template/releases) 查看/下载)
44

@@ -46,17 +46,32 @@
4646

4747
## 更新日志
4848

49+
- 22/09/01 - 22/10/18 (`v1.0.5`)
50+
51+
- 添加了边双连通分量例题
52+
53+
- 添加了可撤销并查集+线段树分治动态判二分图的例题
54+
- 修改了 manacher 一处错误
55+
- 修改了数论基础同余的一处书写错误
56+
- 添加了封装的最小费用最大流模板
57+
- 添加了后缀数组内容
58+
- 添加了 STL 重载 unordered\_set 内容
59+
- 添加了 pollard\_rho 算法
60+
- 添加了斐波那契数列模数循环节结论
61+
- 添加了线性快速幂
62+
- 添加了差分约束算法
63+
4964
- 22/06/10 - 22/08/27 (`v1.0.4`)
5065

5166
- 微改了 STL 的 nth\_element 和 inplace\_merge
52-
67+
5368
- 微改了复杂度一节的排版错误
5469
- 删除了 STL 的 string 重复内容
5570
- 添加了多项式一节,增加 NTT 和分治 FFT 内容
5671
- 修正了线段树区间最值例题表述错误
5772
- 更换了欧拉筛一道例题
5873
- 添加了 tarjan 算法求点双连通分量和圆方树内容
59-
74+
6075
- 22/05/17 - 22/05/25 (`v1.0.3`)
6176

6277
- 增加了stringstream

code/cf813f_segtree_partition.cpp

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
#include <bits/stdc++.h>
2+
const int N = 200000 + 10;
3+
int n, m, ans[N];
4+
struct E
5+
{
6+
int u, v;
7+
E(int a, int b) : u(a), v(b) {}
8+
};
9+
std::map<int, int> g[N];
10+
11+
int L[N << 2], R[N << 2];
12+
std::vector<E> tag[N << 2];
13+
#define lc (o << 1)
14+
#define rc ((o << 1) | 1)
15+
void build(int o, int l, int r)
16+
{
17+
L[o] = l;
18+
R[o] = r;
19+
if (l == r)
20+
return;
21+
int mid = (l + r) >> 1;
22+
build(lc, l, mid);
23+
build(rc, mid + 1, r);
24+
}
25+
// 把一条边拆到logm个区间上去.
26+
// 可以说线段树只是用来保证复杂度的...
27+
void query(int o, int l, int r, const E &e)
28+
{
29+
if (L[o] > r || R[o] < l)
30+
return;
31+
if (l <= L[o] && R[o] <= r)
32+
{
33+
tag[o].push_back(e);
34+
return;
35+
}
36+
query(lc, l, r, e);
37+
query(rc, l, r, e);
38+
}
39+
40+
// merged tree(root=x)->tree(root=y)
41+
struct P
42+
{
43+
int x, y;
44+
P(int a, int b) : x(a), y(b) {}
45+
};
46+
int fa[N], size[N], dis[N];
47+
inline int getpar(int x)
48+
{
49+
while (fa[x] != x)
50+
x = fa[x];
51+
return x;
52+
}
53+
54+
// 到并查集根所经过的边数mod2.
55+
// mod2意义下的加法即为xor.
56+
// 用来查询x和根是不是相同颜色.
57+
inline int getdis(int x)
58+
{
59+
int d = 0;
60+
while (fa[x] != x)
61+
{
62+
d ^= dis[x];
63+
x = fa[x];
64+
}
65+
return d;
66+
}
67+
/// 按照size合并.
68+
inline int solve(int x, int y, std::stack<P> &stk)
69+
{
70+
int dx = getdis(x), dy = getdis(y);
71+
x = getpar(x);
72+
y = getpar(y);
73+
if (x == y)
74+
return (dx ^ dy);
75+
if (size[x] > size[y])
76+
{
77+
std::swap(x, y);
78+
std::swap(dx, dy);
79+
}
80+
size[y] += size[x];
81+
fa[x] = y;
82+
dis[x] = (dx ^ dy ^ 1);
83+
stk.push(P(x, y));
84+
return 1;
85+
}
86+
// 撤销(x->y)的合并.拆出来,size改回去.dis改成0
87+
inline void back(P p)
88+
{
89+
int x = p.x, y = p.y;
90+
size[y] -= size[x];
91+
dis[fa[x] = x] = 0;
92+
}
93+
// 递归线段树,进入区间[l,r]时
94+
// 保证时间轴上[l,r]范围内一直可用的边都被加入了
95+
void dfs(int o, int flag)
96+
{
97+
std::stack<P> stk;
98+
for (auto e : tag[o])
99+
flag &= solve(e.u, e.v, stk);
100+
if (L[o] == R[o])
101+
ans[L[o]] = flag;
102+
else
103+
{
104+
dfs(lc, flag);
105+
dfs(rc, flag);
106+
}
107+
// 撤销操作...不然从爸爸进入兄弟节点的时候开始讲到的那个性质会被破坏.
108+
// 注意撤销顺序...
109+
while (!stk.empty())
110+
{
111+
back(stk.top());
112+
stk.pop();
113+
}
114+
}
115+
116+
int read()
117+
{
118+
int x = 0;
119+
char c;
120+
do
121+
{
122+
c = getchar();
123+
} while (!isdigit(c));
124+
do
125+
{
126+
x = x * 10 + c - '0';
127+
c = getchar();
128+
} while (isdigit(c));
129+
return x;
130+
}
131+
int main()
132+
{
133+
n = read();
134+
m = read();
135+
build(1, 1, m);
136+
int x, y;
137+
for (int i = 1; i <= m; i++)
138+
{
139+
x = read();
140+
y = read();
141+
if (x > y)
142+
std::swap(x, y);
143+
if (g[x][y] == 0)
144+
g[x][y] = i;
145+
else
146+
{
147+
query(1, g[x][y], i - 1, E(x, y));
148+
g[x][y] = 0;
149+
}
150+
}
151+
for (int i = 1; i <= n; i++)
152+
{
153+
size[fa[i] = i] = 1;
154+
for (auto p : g[i])
155+
if (p.second > 0)
156+
query(1, p.second, m, E(i, p.first));
157+
}
158+
dfs(1, 1);
159+
for (int i = 1; i <= m; i++)
160+
puts(ans[i] ? "YES" : "NO");
161+
return 0;
162+
}

code/min_cost_max_flow.cpp

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
#include <bits/stdc++.h>
2+
using namespace std;
3+
using ll = long long;
4+
5+
template <const int mn, class ty = int>
6+
struct MinCostMaxFlow
7+
{
8+
const ty inf = numeric_limits<ty>::max();
9+
struct edge
10+
{
11+
int v;
12+
ty cap, cost;
13+
int rev;
14+
};
15+
vector<edge> g[mn];
16+
ty sum{}, dis[mn]{};
17+
int n, s, t, aug[mn]{};
18+
ty flow{}, cost{};
19+
bool augment()
20+
{
21+
fill(dis, dis + n + 1, inf);
22+
priority_queue<pair<int, int>> q;
23+
dis[t] = 0;
24+
q.push({dis[t], t});
25+
for (int u, v; !q.empty() && q.top().first != inf;)
26+
{
27+
u = q.top().second;
28+
q.pop();
29+
for (auto e : g[u])
30+
{
31+
v = e.v;
32+
if (g[v][e.rev].cap && dis[v] > dis[u] - e.cost)
33+
{
34+
dis[v] = dis[u] - e.cost;
35+
q.push({dis[v], v});
36+
}
37+
}
38+
}
39+
sum += dis[s];
40+
for (int u = 1; u <= n; ++u)
41+
{
42+
for (auto &e : g[u])
43+
{
44+
e.cost += dis[e.v] - dis[u];
45+
}
46+
}
47+
return dis[s] != inf;
48+
}
49+
50+
ty dfs(int u, ty lim)
51+
{
52+
if (u == t)
53+
{
54+
cost += lim * sum;
55+
return lim;
56+
}
57+
ty f = 0;
58+
aug[u] = 1;
59+
for (auto &e : g[u])
60+
{
61+
int v = e.v;
62+
if (!e.cost && e.cap && !aug[v])
63+
{
64+
ty t = dfs(v, min(lim - f, e.cap));
65+
e.cap -= t;
66+
g[v][e.rev].cap += t;
67+
f += t;
68+
if (f == lim)
69+
{
70+
break;
71+
}
72+
}
73+
}
74+
if (f == lim)
75+
{
76+
aug[u] = 0;
77+
}
78+
return f;
79+
}
80+
81+
void add(int u, int v, ty cap, ty cost)
82+
{
83+
g[u].push_back({v, cap, cost, (int)g[v].size()});
84+
g[v].push_back({u, 0, -cost, (int)g[u].size() - 1});
85+
}
86+
87+
pair<ty, ty> solve(int _n, int _s, int _t)
88+
{
89+
n = _n, s = _s, t = _t, flow = cost = 0;
90+
do
91+
{
92+
ty f;
93+
do
94+
{
95+
memset(aug, 0, (n + 1) << 2);
96+
f = dfs(s, inf);
97+
flow += f;
98+
} while (f > 0);
99+
} while (augment());
100+
return {flow, cost};
101+
}
102+
};
103+
104+
const ll mn = 405;
105+
MinCostMaxFlow<mn * 2, int> d;
106+
signed main()
107+
{
108+
cin.tie(0)->ios::sync_with_stdio(false);
109+
int n, m;
110+
char a[mn];
111+
cin >> n >> m;
112+
int s = n + m + 1, t = s + 1;
113+
for (ll i = 1; i <= n; ++i)
114+
{
115+
cin >> (a + 1);
116+
d.add(s, i, 1, 0);
117+
for (ll j = 1; j <= m; ++j)
118+
{
119+
if (a[j] == '1')
120+
{
121+
d.add(i, n + j, 1, 0);
122+
}
123+
}
124+
}
125+
for (ll i = 1; i <= m; ++i)
126+
{
127+
for (ll j = 1; j <= n; ++j)
128+
{
129+
d.add(n + i, t, 1, j);
130+
}
131+
}
132+
auto f = d.solve(t, s, t);
133+
if (f.first != n)
134+
{
135+
cout << -1;
136+
return 0;
137+
}
138+
for (ll i = 1; i <= n; ++i)
139+
{
140+
for (auto e : d.g[i])
141+
{
142+
if (!e.cap && e.v > n)
143+
{
144+
cout << (e.v - n) << ' ';
145+
break;
146+
}
147+
}
148+
}
149+
return 0;
150+
}

0 commit comments

Comments
 (0)