Skip to content
This repository was archived by the owner on Jul 20, 2024. It is now read-only.

Commit d6d06e7

Browse files
committed
Generated Automatically by Workflow.
1 parent acbe0eb commit d6d06e7

7 files changed

Lines changed: 696 additions & 243 deletions

File tree

PDFDocument/part1-Math.pdf

-23 Bytes
Binary file not shown.
26 KB
Binary file not shown.

PDFDocument/part3-String.pdf

36.7 KB
Binary file not shown.

PDFDocument/part4-Geometry.pdf

-17 Bytes
Binary file not shown.

PDFDocument/part5-GraphTheory.pdf

-9 Bytes
Binary file not shown.

TexDocument/part2.tex

Lines changed: 321 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -346,8 +346,11 @@ \subsubsection{区间加/区间求和}\label{ux533aux95f4ux52a0ux533aux95f4ux6c4
346346
}
347347
\end{minted}
348348

349+
\hypertarget{ux7ebfux6bb5ux6811ux6a21ux677f}{%
350+
\subsection{5.线段树模板}\label{ux7ebfux6bb5ux6811ux6a21ux677f}}
351+
349352
\hypertarget{ux6734ux7d20ux7ebfux6bb5ux6811}{%
350-
\subsection{4.朴素线段树}\label{ux6734ux7d20ux7ebfux6bb5ux6811}}
353+
\subsubsection{(1).朴素线段树}\label{ux6734ux7d20ux7ebfux6bb5ux6811}}
351354

352355
区间和:区间修改/单点修改/单点查询/区间查询
353356

@@ -419,7 +422,7 @@ \subsection{4.朴素线段树}\label{ux6734ux7d20ux7ebfux6bb5ux6811}}
419422
\end{minted}
420423

421424
\hypertarget{ux52a8ux6001ux5f00ux70b9ux7ebfux6bb5ux6811}{%
422-
\subsection{5.动态开点线段树}\label{ux52a8ux6001ux5f00ux70b9ux7ebfux6bb5ux6811}}
425+
\subsubsection{(2).动态开点线段树}\label{ux52a8ux6001ux5f00ux70b9ux7ebfux6bb5ux6811}}
423426

424427
\begin{minted}[fontsize=\footnotesize,breaklines,linenos]{cpp}
425428
namespace SegmentTree{
@@ -1942,8 +1945,8 @@ \subsection{13.CDQ 分治}\label{cdq-ux5206ux6cbb}}
19421945

19431946
\end{minted}
19441947

1945-
\hypertarget{ux73c2ux6735ux8389ux6811ux8001ux53f8ux673aux6811}{%
1946-
\subsection{14.珂朵莉树/老司机树}\label{ux73c2ux6735ux8389ux6811ux8001ux53f8ux673aux6811}}
1948+
\hypertarget{ux73c2ux6735ux8389ux6811ux8001ux53f8ux673aux6811ux533aux95f4ux63a8ux5e73}{%
1949+
\subsection{14.珂朵莉树/老司机树(区间推平)}\label{ux73c2ux6735ux8389ux6811ux8001ux53f8ux673aux6811ux533aux95f4ux63a8ux5e73}}
19471950

19481951
\begin{minted}[fontsize=\footnotesize,breaklines,linenos]{cpp}
19491952
struct node{
@@ -2035,8 +2038,319 @@ \subsection{14.珂朵莉树/老司机树}\label{ux73c2ux6735ux8389ux6811ux8001ux
20352038
}
20362039
\end{minted}
20372040

2041+
\hypertarget{ux66ffux7f6aux7f8aux6811ux66b4ux529bux91cdux6784ux4e8cux53c9ux641cux7d22ux6811}{%
2042+
\subsection{15.替罪羊树(暴力重构二叉搜索树)}\label{ux66ffux7f6aux7f8aux6811ux66b4ux529bux91cdux6784ux4e8cux53c9ux641cux7d22ux6811}}
2043+
2044+
很暴力但是很牛逼的结构,平衡系数一般置为\(0.75\)即可。注意,二叉搜索树本质不变,所有二叉搜索树性质仍然适用。
2045+
2046+
平衡系数越大插入速度就越快,而访问和删除速度就会降低。反之则插入变慢
2047+
2048+
\begin{minted}[fontsize=\footnotesize,breaklines,linenos]{cpp}
2049+
const int N = 2e5 + 10;
2050+
double alpha = 0.75; //平衡系数
2051+
2052+
namespace SGT {
2053+
struct node {
2054+
int ls, rs;
2055+
int w, wn, s, sz, sd;
2056+
} tree[N];
2057+
2058+
int cnt, root;
2059+
2060+
//* recalculate the value of rt
2061+
void calc(int rt) {
2062+
tree[rt].s = tree[tree[rt].ls].s + tree[tree[rt].rs].s + 1;
2063+
tree[rt].sz = tree[tree[rt].ls].sz + tree[tree[rt].rs].sz + tree[rt].wn;
2064+
tree[rt].sd = tree[tree[rt].ls].sd + tree[tree[rt].rs].sd + (tree[rt].wn != 0);
2065+
}
2066+
2067+
//* determine if node k needs to be rebuild
2068+
bool can_rebuild(int rt) {
2069+
return tree[rt].wn && (alpha * tree[rt].s <= (double)max(tree[tree[rt].ls].s, tree[tree[rt].rs].s) || (double)tree[rt].sd <= alpha * tree[rt].s);
2070+
}
2071+
2072+
int ldr[N];
2073+
2074+
//* flatten the sub-tree of node rt in medium-order traversal
2075+
void rebuild_nf(int &ldc, int rt) {
2076+
if(!rt) return;
2077+
rebuild_nf(ldc, tree[rt].ls);
2078+
if(tree[rt].wn) ldr[ldc++] = rt;
2079+
rebuild_nf(ldc, tree[rt].rs); // if the current node has been deleted, then no retained it.
2080+
}
2081+
2082+
//* rebuild the part [l, r] to a binary search tree(in array ldr)
2083+
int rebuild_bd(int l, int r) {
2084+
if(l >= r) return 0;
2085+
int mid = l + r >> 1; // choose the mid value as the root to make it balanced
2086+
tree[ldr[mid]].ls = rebuild_bd(l, mid);
2087+
tree[ldr[mid]].rs = rebuild_bd(mid + 1, r);
2088+
calc(ldr[mid]);
2089+
return ldr[mid];
2090+
}
2091+
2092+
//* rebuild the sub-tree of node rt
2093+
void rebuild(int &rt) {
2094+
int ldc = 0;
2095+
rebuild_nf(ldc, rt);
2096+
rt = rebuild_bd(0, ldc);
2097+
}
2098+
2099+
//* insert a node ot the subtree of rt with value k
2100+
void insert(int &rt, int k) {
2101+
if(!rt) {
2102+
rt = ++cnt;
2103+
if(!root) root = 1;
2104+
tree[rt].w = k;
2105+
tree[rt].ls = tree[rt].rs = 0;
2106+
tree[rt].wn = tree[rt].s = tree[rt].sz = tree[rt].sd = 1;
2107+
} else {
2108+
if(tree[rt].w == k) tree[rt].wn++;
2109+
else if(tree[rt].w < k) insert(tree[rt].rs, k);
2110+
else insert(tree[rt].ls, k);
2111+
calc(rt);
2112+
if(can_rebuild(rt)) rebuild(rt);
2113+
}
2114+
}
2115+
2116+
//* delete the node with value k from the sub-tree of k
2117+
void del(int &rt, int k) {
2118+
if(!rt) return;
2119+
if(tree[rt].w == k) {
2120+
if(tree[rt].wn) tree[rt].wn--;
2121+
} else {
2122+
if(tree[rt].w < k) del(tree[rt].rs, k);
2123+
else del(tree[rt].ls, k);
2124+
}
2125+
calc(rt);
2126+
if(can_rebuild(rt)) rebuild(rt);
2127+
}
2128+
2129+
//* find the lowest ranking with a weight strictly greater than k
2130+
int upper_min(int rt, int k) {
2131+
if(!rt) return 1;
2132+
else if(tree[rt].w == k && tree[rt].wn)
2133+
return tree[tree[rt].ls].sz + tree[rt].wn + 1;
2134+
else if(tree[rt].w > k)
2135+
return upper_min(tree[rt].ls, k);
2136+
else
2137+
return tree[tree[rt].ls].sz + tree[rt].wn + upper_min(tree[rt].rs, k);
2138+
}
2139+
2140+
//* find the maximum ranking with a weight strictly less than k
2141+
int lower_max(int rt, int k) {
2142+
if(!rt) return 0;
2143+
else if(tree[rt].w == k && tree[rt].wn)
2144+
return tree[tree[rt].ls].sz;
2145+
else if(tree[rt].w < k)
2146+
return tree[tree[rt].ls].sz + tree[rt].wn + lower_max(tree[rt].rs, k);
2147+
else
2148+
return lower_max(tree[rt].ls, k);
2149+
}
2150+
2151+
//* find the exactly value of rank k
2152+
int getk(int rt, int k) {
2153+
if(!rt) return 0;
2154+
else if(tree[tree[rt].ls].sz < k && k <= tree[tree[rt].ls].sz + tree[rt].wn)
2155+
return tree[rt].w;
2156+
else if(tree[tree[rt].ls].sz + tree[rt].wn < k)
2157+
return getk(tree[rt].rs, k - tree[tree[rt].ls].sz - tree[rt].wn);
2158+
else
2159+
return getk(tree[rt].ls, k);
2160+
}
2161+
2162+
inline int find_pre(int rt, int k) {
2163+
return getk(rt, lower_max(rt, k));
2164+
}
2165+
2166+
inline int find_aft(int rt, int k) {
2167+
return getk(rt, upper_min(rt, k));
2168+
}
2169+
}
2170+
2171+
using SGT::root;
2172+
2173+
inline void solve() {
2174+
int n = 0; cin >> n;
2175+
for(int i = 1; i <= n; i++) {
2176+
int op, x; cin >> op >> x;
2177+
if(op == 1) SGT::insert(root, x);
2178+
else if(op == 2){
2179+
SGT::del(root, x);
2180+
}
2181+
else if(op == 3) {
2182+
int rnk = SGT::lower_max(root, x) + 1;
2183+
cout << rnk << endl;
2184+
} else if(op == 4) {
2185+
int k = SGT::getk(root, x);
2186+
cout << k << endl;
2187+
} else if(op == 5) {
2188+
int pre = SGT::find_pre(root, x);
2189+
cout << pre << endl;
2190+
} else if(op == 6) {
2191+
int aft = SGT::find_aft(root, x);
2192+
cout << aft << endl;
2193+
}
2194+
}
2195+
}
2196+
\end{minted}
2197+
2198+
\hypertarget{splay}{%
2199+
\subsection{16.Splay}\label{splay}}
2200+
2201+
\begin{minted}[fontsize=\footnotesize,breaklines,linenos]{cpp}
2202+
#include <cstdio>
2203+
const int N = 100005;
2204+
int rt, tot, fa[N], ch[N][2], val[N], cnt[N], sz[N];
2205+
2206+
struct Splay{
2207+
void maintain(int x) { sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + cnt[x]; }
2208+
2209+
bool get(int x) { return x == ch[fa[x]][1]; }
2210+
2211+
void clear(int x) {
2212+
ch[x][0] = ch[x][1] = fa[x] = val[x] = sz[x] = cnt[x] = 0;
2213+
}
2214+
2215+
void rotate(int x){
2216+
int y = fa[x], z = fa[y], chk = get(x);
2217+
ch[y][chk] = ch[x][chk ^ 1];
2218+
if (ch[x][chk ^ 1]) fa[ch[x][chk ^ 1]] = y;
2219+
ch[x][chk ^ 1] = y;
2220+
fa[y] = x, fa[x] = z;
2221+
if (z) ch[z][y == ch[z][1]] = x;
2222+
maintain(x), maintain(y);
2223+
}
2224+
2225+
void splay(int x){
2226+
for (int f = fa[x]; f = fa[x], f; rotate(x))
2227+
if (fa[f]) rotate(get(x) == get(f) ? f : x);
2228+
rt = x;
2229+
}
2230+
2231+
void insert(int k){
2232+
if (!rt){
2233+
val[++tot] = k, cnt[tot]++;
2234+
rt = tot;
2235+
maintain(rt);
2236+
return;
2237+
}
2238+
int cur = rt, f = 0;
2239+
while (1){
2240+
if (val[cur] == k){
2241+
cnt[cur]++;
2242+
maintain(cur), maintain(f);
2243+
splay(cur);
2244+
break;
2245+
}
2246+
f = cur, cur = ch[cur][val[cur] < k];
2247+
if (!cur){
2248+
val[++tot] = k, cnt[tot]++, fa[tot] = f;
2249+
ch[f][val[f] < k] = tot;
2250+
maintain(tot), maintain(f);
2251+
splay(tot);
2252+
break;
2253+
}
2254+
}
2255+
}
2256+
2257+
int rk(int k){
2258+
int res = 0, cur = rt;
2259+
while (1){
2260+
if (k < val[cur]){
2261+
cur = ch[cur][0];
2262+
}
2263+
else{
2264+
res += sz[ch[cur][0]];
2265+
if (k == val[cur]){
2266+
splay(cur);
2267+
return res + 1;
2268+
}
2269+
res += cnt[cur], cur = ch[cur][1];
2270+
}
2271+
}
2272+
}
2273+
2274+
int kth(int k){
2275+
int cur = rt;
2276+
while (1){
2277+
if (ch[cur][0] && k <= sz[ch[cur][0]]) cur = ch[cur][0];
2278+
else{
2279+
k -= cnt[cur] + sz[ch[cur][0]];
2280+
if (k <= 0){
2281+
splay(cur);
2282+
return val[cur];
2283+
}
2284+
cur = ch[cur][1];
2285+
}
2286+
}
2287+
}
2288+
2289+
int pre(){
2290+
int cur = ch[rt][0];
2291+
if (!cur) return cur;
2292+
while (ch[cur][1]) cur = ch[cur][1];
2293+
splay(cur);
2294+
return cur;
2295+
}
2296+
2297+
int nxt(){
2298+
int cur = ch[rt][1];
2299+
if (!cur) return cur;
2300+
while (ch[cur][0]) cur = ch[cur][0];
2301+
splay(cur);
2302+
return cur;
2303+
}
2304+
2305+
void del(int k){
2306+
rk(k);
2307+
if (cnt[rt] > 1) {
2308+
cnt[rt]--;
2309+
maintain(rt);
2310+
return;
2311+
}
2312+
if (!ch[rt][0] && !ch[rt][1]){
2313+
clear(rt);
2314+
rt = 0;
2315+
return;
2316+
}
2317+
if (!ch[rt][0]) {
2318+
int cur = rt;
2319+
rt = ch[rt][1], fa[rt] = 0;
2320+
clear(cur);
2321+
return;
2322+
}
2323+
if (!ch[rt][1]) {
2324+
int cur = rt;
2325+
rt = ch[rt][0], fa[rt] = 0;
2326+
clear(cur);
2327+
return;
2328+
}
2329+
int cur = rt, x = pre();
2330+
fa[ch[cur][1]] = x;
2331+
ch[x][1] = ch[cur][1];
2332+
clear(cur);
2333+
maintain(rt);
2334+
}
2335+
} tree;
2336+
2337+
int main(){
2338+
int n, opt, x;
2339+
for (scanf("%d", &n); n; --n){
2340+
scanf("%d%d", &opt, &x);
2341+
if (opt == 1) tree.insert(x);
2342+
else if (opt == 2) tree.del(x);
2343+
else if (opt == 3) printf("%d\n", tree.rk(x));
2344+
else if (opt == 4) printf("%d\n", tree.kth(x));
2345+
else if (opt == 5) tree.insert(x), printf("%d\n", val[tree.pre()]), tree.del(x);
2346+
else tree.insert(x), printf("%d\n", val[tree.nxt()]), tree.del(x);
2347+
}
2348+
return 0;
2349+
}
2350+
\end{minted}
2351+
20382352
\hypertarget{link-cut-tree}{%
2039-
\subsection{15.Link Cut Tree}\label{link-cut-tree}}
2353+
\subsection{17.Link Cut Tree}\label{link-cut-tree}}
20402354

20412355
\hypertarget{ux65e0ux6839ux6811ux7248ux672cmakeroot}{%
20422356
\subsubsection{(1).无根树版本(MakeRoot)}\label{ux65e0ux6839ux6811ux7248ux672cmakeroot}}
@@ -2411,8 +2725,8 @@ \subsubsection{哈希表}\label{ux54c8ux5e0cux8868}}
24112725
cc_hash_table<int, int> mp;
24122726
\end{minted}
24132727

2414-
\hypertarget{zkwux7ebfux6bb5ux6811ux4e0dux5e26ux4feermqonlog-log-no1}{%
2415-
\subsection{\texorpdfstring{ZKW线段树+不带修RMQ(\(O(N\log \log N)+O(1)\))}{ZKW线段树+不带修RMQ(O(N\textbackslash log \textbackslash log N)+O(1))}}\label{zkwux7ebfux6bb5ux6811ux4e0dux5e26ux4feermqonlog-log-no1}}
2728+
\hypertarget{ux9644ux5f55zkwux7ebfux6bb5ux6811ux4e0dux5e26ux4feermqonlog-log-no1}{%
2729+
\subsection{\texorpdfstring{附录:ZKW线段树+不带修RMQ(\(O(N\log \log N)+O(1)\))}{附录:ZKW线段树+不带修RMQ(O(N\textbackslash log \textbackslash log N)+O(1))}}\label{ux9644ux5f55zkwux7ebfux6bb5ux6811ux4e0dux5e26ux4feermqonlog-log-no1}}
24162730

24172731
普通的 zkw 线段树解法分为线性建树和单次 \(O(logn)\)
24182732
的查询,显然查询是瓶颈。

0 commit comments

Comments
 (0)