Skip to content

Commit 311482c

Browse files
committed
[MIsc]
1 parent 00232e0 commit 311482c

12 files changed

+509
-25
lines changed

DSA/Notes.md

+8-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
并查集 Disjoint-set
1+
### 并查集 Disjoint-set
22
- [oi-wiki](https://oi-wiki.org/ds/dsu/)
33
- 每个集合用一棵树来表示, 树根的编号就是整个集合的编号
44
- 每个结点存储其父结点 `p[x]`
@@ -20,9 +20,9 @@
2020
[Almost Union-Find](https://onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=229&page=show_problem&problem=3138)
2121

2222
### 树状数组 Binary Indexed Tree
23-
[oi-wiki: Binary Indexed Tree](https://oi-wiki.org/ds/fenwick/)
24-
[wikipedia: Fenwick_tree](https://en.wikipedia.org/wiki/Fenwick_tree)
25-
[五分钟丝滑动画讲解 | 树状数组](https://www.bilibili.com/video/BV1ce411u7qP/)
23+
- [oi-wiki: Binary Indexed Tree](https://oi-wiki.org/ds/fenwick/)
24+
- [wikipedia: Fenwick_tree](https://en.wikipedia.org/wiki/Fenwick_tree)
25+
- [五分钟丝滑动画讲解 | 树状数组](https://www.bilibili.com/video/BV1ce411u7qP/)
2626

2727
- 单点修改, 区间查询 (基础)
2828
- 区间修改, 单点查询: 查分数组
@@ -33,7 +33,10 @@
3333
- 离线处理: 读取所有查询, 统一处理, 统一输出
3434

3535
### 线段树 Segment Tree
36-
36+
- [wikipedia:Segment Tree](https://en.wikipedia.org/wiki/Segment_tree)
37+
- [CF: SegTree](https://codeforces.com/blog/entry/57319)
38+
- [usaco](https://usaco.guide/adv/segtree-beats?lang=cpp)
39+
- [hackerearth](https://www.hackerearth.com/practice/data-structures/advanced-data-structures/segment-trees/tutorial/)
3740
- 分治 + 二叉树 + Lazy-Tag
3841
- 大区间的解可通过小区间的解合并而得
3942
- 单点修改 + 区间查询 (Base)

DSA/SegmentTree/AW1275.cpp

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/* 最大数
2+
3+
*/
4+
#include <bits/stdc++.h>
5+
using namespace std;
6+
7+
const size_t N = 2e5 + 10;
8+
size_t m;
9+
int p;
10+
int a;
11+
12+
13+
14+
int main() {
15+
cin >> m >> p;
16+
17+
}

DSA/SegmentTree/AW1275_noted.cpp

+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
作者:random_srand
3+
链接:https://www.acwing.com/solution/content/33974/
4+
来源:AcWing
5+
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
6+
*/
7+
8+
#include <iostream>
9+
using namespace std;
10+
11+
const int N = 2e5 + 5;
12+
typedef long long LL;
13+
14+
// 线段树的结点, 最大空间开4倍
15+
struct Node {
16+
int l, r;
17+
int v; // 最大值
18+
} tr[N * 4];
19+
20+
int m, p;
21+
22+
// u为当前线段树的结点编号
23+
void build(int u, int l, int r) {
24+
tr[u] = { l, r };
25+
if(l == r) return;
26+
int mid = l + r >> 1;
27+
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
28+
}
29+
30+
// 查询以u为根节点,区间[l, r]中的最大值
31+
int query(int u, int l, int r) {
32+
// Tl-----Tr
33+
// L-------------R
34+
// 1.不必分治,直接返回
35+
if(tr[u].l >= l && tr[u].r <= r) return tr[u].v;
36+
37+
int mid = tr[u].l + tr[u].r >> 1;
38+
int v = 0;
39+
// Tl----m----Tr
40+
// L-------------R
41+
// 2.需要在tr的左区间[Tl, m]继续分治
42+
if(l <= mid) v = query(u << 1, l, r);
43+
44+
// Tl----m----Tr
45+
// L---------R
46+
// 3.需要在tr的右区间(m, Tr]继续分治
47+
if(r > mid) v = max(v, query(u << 1 | 1, l, r));
48+
49+
// Tl----m----Tr
50+
// L-----R
51+
// 2.3涵盖了这种情况
52+
return v;
53+
}
54+
55+
// u为结点编号,更新该结点的区间最大值
56+
void modify(int u, int x, int v) {
57+
if(tr[u].l == tr[u].r)
58+
tr[u].v = v; // 叶节点,递归出口
59+
else {
60+
int mid = tr[u].l + tr[u].r >> 1;
61+
// 分治处理左右子树, 寻找x所在的子树
62+
if(x <= mid)
63+
modify(u << 1, x, v);
64+
else
65+
modify(u << 1 | 1, x, v);
66+
// 回溯,拿子结点的信息更新父节点, 即pushup操作
67+
tr[u].v = max(tr[u << 1].v, tr[u << 1 | 1].v);
68+
}
69+
}
70+
71+
int main() {
72+
// n表示树中的结点个数, last保存上一次查询的结果
73+
int n = 0, last = 0;
74+
cin >> m >> p;
75+
76+
// 初始化线段树, 结点的区间最多为[1, m]。
77+
build(1, 1, m);
78+
79+
while(m--) {
80+
char op;
81+
cin >> op;
82+
if(op == 'A') // 添加结点
83+
{
84+
int t;
85+
cin >> t;
86+
// 在n + 1处插入
87+
modify(1, n + 1, ((LL)t + last) % p);
88+
// 结点个数+1
89+
n++;
90+
} else {
91+
int L;
92+
cin >> L;
93+
// 查询[n - L + 1, n]内的最大值,u = 1,即从根节点开始查询
94+
last = query(1, n - L + 1, n);
95+
cout << last << endl;
96+
}
97+
}
98+
99+
return 0;
100+
}

DSA/SegmentTree/LuoGu3372.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,15 @@ int main() {
9292
}
9393
}
9494
/*
95+
96+
5 5
97+
1 5 4 2 3
98+
2 2 4
99+
1 2 3 2
100+
2 3 4
101+
1 1 5 1
102+
2 1 4
103+
95104
11
96105
8
97106
20

DSA/SegmentTree/LuoGu3372_New.cpp

Whitespace-only changes.

DSA/SegmentTree/SegTreeTemplate.cpp

+227
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
#include <bits/stdc++.h>
2+
using namespace std;
3+
4+
#define ls(x) ((x) << 1)
5+
#define rs(x) (((x) << 1) | 1)
6+
#define mid(l, r) (((l) + (r)) >> 1)
7+
8+
typedef pair<size_t, size_t> Interval;
9+
10+
bool isInterSect(Interval r1, Interval r2) {
11+
if(r1.first > r2.first) swap(r1, r2);
12+
/* r1.first <= r2.first */
13+
if(r1.second >= r2.first) return true;
14+
return false;
15+
}
16+
17+
template <typename T>
18+
class SegTree {
19+
private:
20+
vector<T> tree, tag;
21+
// int n, n4;
22+
23+
const vector<T>& arrRef;
24+
const size_t mRoot = 1, mRootStart = 1, mRootEnd;
25+
26+
void build(const size_t root, const size_t start, const size_t end);
27+
void pushup(const size_t root);
28+
void pushdown(const size_t root, const size_t curStart,
29+
const size_t curEnd);
30+
void addtag(const size_t root, const size_t curStart, const size_t curEnd,
31+
const T val);
32+
void intervalUpdateImpl(const size_t start, const size_t end, const T val,
33+
const size_t root, const size_t curStart,
34+
const size_t curEnd);
35+
T getIntervalSumImpl(const size_t start, const size_t end,
36+
const size_t root, const size_t curStart,
37+
const size_t curEnd);
38+
39+
public:
40+
SegTree(const vector<T>& arr)
41+
: mRootEnd(arr.size()), arrRef(arr), tree(arr.size() << 2, 0),
42+
tag(arr.size() << 2, 0) {
43+
/* idx start from 1*/
44+
assert(arr.size() >= 1 and arr.at(0) == 0);
45+
build(mRoot, mRootStart, mRootEnd);
46+
}
47+
48+
void intervalUpdate(const size_t start, const size_t end, const T val);
49+
50+
T getIntervalSum(const size_t start, const size_t end);
51+
};
52+
template <typename T>
53+
void SegTree<T>::build(const size_t root, const size_t start,
54+
const size_t end) {
55+
/* leaf node */
56+
if(start == end) {
57+
tree[root] = arrRef[start];
58+
return;
59+
}
60+
/* divide */
61+
const size_t Mid = mid(start, end);
62+
63+
build(ls(root), start, Mid);
64+
build(rs(root), Mid + 1, end);
65+
/* calc root */
66+
pushup(root);
67+
}
68+
template <typename T>
69+
void SegTree<T>::pushup(const size_t root) {
70+
/* gather children value, push up to root */
71+
/* interval sum */
72+
tree[root] = tree[ls(root)] + tree[rs(root)];
73+
/* max/min */
74+
// tree[root] = min(tree[ls(root)], tree[rs(root)]);
75+
}
76+
template <typename T>
77+
void SegTree<T>::pushdown(const size_t root, const size_t curStart,
78+
const size_t curEnd) {
79+
/* push root tag to children,
80+
because we need to update child interval of root,
81+
so the tag of root will be invalid,
82+
but its children must record root's tag */
83+
if(tag[root]) {
84+
const size_t curMid = mid(curStart, curEnd);
85+
addtag(ls(root), curStart, curMid, tag[root]);
86+
addtag(rs(root), curMid + 1, curEnd, tag[root]);
87+
tag[root] = 0;
88+
}
89+
}
90+
91+
template <typename T>
92+
void SegTree<T>::addtag(const size_t root, const size_t curStart,
93+
const size_t curEnd, const T val) {
94+
assert(curStart <= curEnd);
95+
tag[root] += val;
96+
tree[root] += val * (curEnd - curStart + 1);
97+
}
98+
template <typename T>
99+
void SegTree<T>::intervalUpdate(const size_t start, const size_t end,
100+
const T val) {
101+
intervalUpdateImpl(start, end, val, mRoot, mRootStart, mRootEnd);
102+
}
103+
template <typename T>
104+
void SegTree<T>::intervalUpdateImpl(const size_t start, const size_t end,
105+
const T val, const size_t root,
106+
const size_t curStart,
107+
const size_t curEnd) {
108+
assert(curStart <= curEnd);
109+
/* assert Intersect */
110+
assert(isInterSect({ start, end }, { curStart, curEnd }));
111+
/* query interval complete cover cur node interval
112+
** start <= curStart ~ curEnd <= end */
113+
if(start <= curStart and curEnd <= end) {
114+
addtag(root, curStart, curEnd, val);
115+
return;
116+
}
117+
/* else: cur Interval of root is not in [start, end],
118+
** need divide and conquer */
119+
/* firstly, pushdown root tag to children */
120+
pushdown(root, curStart, curEnd);
121+
/* then recursively divide and conquer */
122+
const size_t curMid = mid(curStart, curEnd);
123+
/* left child tree */
124+
if(curMid >= start)
125+
intervalUpdateImpl(start, end, val, ls(root), curStart, curMid);
126+
/* right child tree */
127+
if(curMid + 1 <= end)
128+
intervalUpdateImpl(start, end, val, rs(root), curMid + 1, curEnd);
129+
/* update root */
130+
pushup(root);
131+
}
132+
template <typename T>
133+
T SegTree<T>::getIntervalSumImpl(const size_t start, const size_t end,
134+
const size_t root, const size_t curStart,
135+
const size_t curEnd) {
136+
assert(curStart <= curEnd);
137+
138+
/* query interval complete cover cur node interval, return tree[root]
139+
start <= curStart and curEnd <= end */
140+
if(start <= curStart and curEnd <= end) { return tree[root]; }
141+
/* not complete cover */
142+
pushdown(root, curStart, curEnd);
143+
T res = 0;
144+
const size_t curMid = mid(curStart, curEnd);
145+
if(curMid >= start)
146+
res += getIntervalSumImpl(start, end, ls(root), curStart, curMid);
147+
if(curMid + 1 <= end)
148+
res += getIntervalSumImpl(start, end, rs(root), curMid + 1, curEnd);
149+
return res;
150+
}
151+
template <typename T>
152+
T SegTree<T>::getIntervalSum(const size_t start, const size_t end) {
153+
return getIntervalSumImpl(start, end, mRoot, mRootStart, mRootEnd);
154+
}
155+
bool debug = true;
156+
157+
void testSegTree() {
158+
vector<int> arr = { 0, 1, 2, 3, 4, 5, 6 };
159+
SegTree<int> segtree(arr);
160+
function<void(const size_t start, const size_t end, bool debug)>
161+
testIntervalSum;
162+
function<void(const size_t start, const size_t end, const int val)>
163+
testIntervalUpdate;
164+
165+
testIntervalSum = [&arr, &segtree](const size_t start, const size_t end,
166+
bool debug) {
167+
auto stdAns = accumulate(arr.begin() + start, arr.begin() + end + 1, 0);
168+
auto stAns = segtree.getIntervalSum(start, end);
169+
if(stdAns != stAns) { cout << "wrong ans!" << endl; }
170+
if(debug) {
171+
cout << "test Interval Sum: [" << start << ", " << end << "]"
172+
<< endl;
173+
cout << "Standerd Ans: " << stdAns << endl;
174+
cout << "SegTree Ans " << stdAns << endl;
175+
}
176+
};
177+
for(int s = 1; s <= arr.size(); s++) {
178+
for(int e = s; e <= arr.size(); e++) { testIntervalSum(s, e, false); }
179+
}
180+
181+
testIntervalUpdate = [&arr, &segtree, testIntervalSum](const size_t start,
182+
const size_t end,
183+
const int val) {
184+
//
185+
for(int i = start; i <= end; i++) { arr[i] += val; }
186+
cout << "arr: " << endl;
187+
for(int i = 0; i < arr.size(); i++) { cout << arr[i] << " "; }
188+
cout << endl;
189+
segtree.intervalUpdate(start, end, val);
190+
testIntervalSum(start, end, true);
191+
};
192+
testIntervalUpdate(1, 2, 5);
193+
testIntervalUpdate(1, 3, -2);
194+
testIntervalUpdate(2, 2, 1);
195+
testIntervalUpdate(5, 5, -3);
196+
}
197+
198+
typedef uint64_t ull;
199+
typedef int64_t ll;
200+
201+
const int N = 1e5 + 10;
202+
size_t n, m;
203+
vector<ll> arr(N);
204+
205+
int main() {
206+
cin >> n >> m;
207+
for(int i = 1; i <= n; i++) { cin >> arr[i]; }
208+
arr.resize(n + 1);
209+
SegTree<ll> segtree(arr);
210+
while(m--) {
211+
int q, x, y;
212+
cin >> q;
213+
if(q == 1) {
214+
/* 1 x y k */
215+
ll k;
216+
cin >> x >> y >> k;
217+
segtree.intervalUpdate(x, y, k);
218+
} else if(q == 2) {
219+
cin >> x >> y;
220+
cout << segtree.getIntervalSum(x, y) << endl;
221+
} else {
222+
assert(false);
223+
}
224+
}
225+
226+
return 0;
227+
}

0 commit comments

Comments
 (0)