├── .clang-format ├── .gitignore ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── main.py ├── src ├── ds │ ├── AVLTree.cpp │ ├── BTree.cpp │ ├── CDQ.cpp │ ├── CaptainMo.cpp │ ├── CartesianTree.cpp │ ├── DSU.cpp │ ├── FenwickTree.cpp │ ├── KDTree.cpp │ ├── LefitstTree.cpp │ ├── LinkCutTree.cpp │ ├── PersistentSegmentTree.cpp │ ├── RMQ.cpp │ ├── RedBlackTree.cpp │ ├── RollBackCaptainMo.cpp │ ├── ScapegoatTree.cpp │ ├── SegmentTree.cpp │ ├── SplayValue.cpp │ ├── TreapRange.cpp │ ├── TreapValue.cpp │ └── WDSU.cpp ├── geometry │ ├── 2DGeometry.cpp │ ├── 3DGeometry.cpp │ ├── CloestPair2DLinear.cpp │ └── ClosestPair2D.cpp ├── graph │ ├── BiGraphMatch.cpp │ ├── BiWraphMatch.cpp │ ├── BlockForest.cpp │ ├── BlockTree.cpp │ ├── Dijkstra.cpp │ ├── EdgeBCC.cpp │ ├── ExKruskal.cpp │ ├── Graph.cpp │ ├── GraphMatch.cpp │ ├── HLD-Edge.cpp │ ├── HolmDeLichtenbergThorup.cpp │ ├── KosarajuSCC.cpp │ ├── Kruskal.cpp │ ├── LCA-HLD.cpp │ ├── LCA.cpp │ ├── PointBCC.cpp │ ├── SPFA.cpp │ ├── TarjanSCC.cpp │ ├── TwoSAT.cpp │ ├── Wraph.cpp │ ├── WraphMatch.cpp │ ├── dsu-on-tree.cpp │ ├── maxflow.cpp │ ├── mincostflow.cpp │ └── tree-divide.cpp ├── math │ ├── BSGS.cpp │ ├── BigInteger.cpp │ ├── CRT.cpp │ ├── Cipolla.cpp │ ├── EXGCD.cpp │ ├── EulerSeive.cpp │ ├── FFT.cpp │ ├── FWT.cpp │ ├── LinearBasis.cpp │ ├── Lucas.cpp │ ├── Matrix.cpp │ ├── Mobius.cpp │ ├── Modular.cpp │ ├── Modular2.cpp │ ├── NTT.cpp │ ├── PollardRho.cpp │ ├── Polynomial.cpp │ ├── PowerfulNumber.cpp │ ├── Simplex.cpp │ ├── SimpsonIntegral.cpp │ ├── du.cpp │ ├── eval.cpp │ └── min25.cpp ├── misc │ └── STLWrapper.cpp ├── other │ ├── BFPRT.cpp │ ├── SimulateAnneal.cpp │ ├── debug.h │ ├── java-header.java │ ├── main.cpp │ └── to_string.h └── string │ ├── ACAM.cpp │ ├── GSAM.cpp │ ├── KMP.cpp │ ├── Manacher.cpp │ ├── PAM.cpp │ ├── SAIS.cpp │ ├── SAM.cpp │ ├── SqAM.cpp │ ├── StringHash.cpp │ ├── SuffixBST.cpp │ ├── SufixArray.cpp │ ├── Trie.cpp │ └── ZAlgorithm.cpp ├── template.pdf ├── template.tex └── tex ├── config.yml ├── head └── tail /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | BasedOnStyle: Chromium 4 | ColumnLimit: 0 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "latex-workshop.intellisense.package.enabled": true, 3 | "latex-workshop.intellisense.unimathsymbols.enabled": true, 4 | "latex-workshop.latex.recipes": [ 5 | { 6 | "name": "xelatex", 7 | "tools": ["xelatex"] 8 | }, 9 | { 10 | "name": "latexmk", 11 | "tools": ["latexmk"] 12 | }, 13 | { 14 | "name": "xelatex -> bibtex -> xelatex", 15 | "tools": ["xelatex", "bibtex", "xelatex"] 16 | }, 17 | { 18 | "name": "xelatex -> biber -> xelatex", 19 | "tools": ["xelatex", "biber", "xelatex"] 20 | }, 21 | { 22 | "name": "make thesis (Linux/macOS)", 23 | "tools": ["make-thesis"] 24 | } 25 | ], 26 | 27 | "latex-workshop.latex.tools": [ 28 | { 29 | "name": "latexmk", 30 | "command": "latexmk", 31 | "args": [ 32 | "-shell-escape", 33 | "-file-line-error", 34 | "-halt-on-error", 35 | "-interaction=nonstopmode", 36 | "%DOC%" 37 | ] 38 | }, 39 | { 40 | "name": "xelatex", 41 | "command": "xelatex", 42 | "args": [ 43 | "-synctex=1", 44 | "-interaction=nonstopmode", 45 | "-file-line-error", 46 | "-shell-escape", 47 | "%DOC%" 48 | ] 49 | }, 50 | { 51 | "name": "bibtex", 52 | "command": "bibtex", 53 | "args": ["%DOCFILE%"] 54 | }, 55 | { 56 | "name": "biber", 57 | "command": "biber", 58 | "args": ["%DOCFILE%"] 59 | }, 60 | { 61 | "name": "make-thesis", 62 | "command": "make", 63 | "args": [], 64 | "env": {} 65 | } 66 | ], 67 | "latex-workshop.view.pdf.viewer": "tab", 68 | "latex-workshop.latex.clean.fileTypes": [ 69 | "*.aux", 70 | "*.bbl", 71 | "*.bcf", 72 | "*.blg", 73 | "*.idx", 74 | "*.ind", 75 | "*.lof", 76 | "*.lot", 77 | "*.out", 78 | "*.toc", 79 | "*.acn", 80 | "*.acr", 81 | "*.alg", 82 | "*.glg", 83 | "*.glo", 84 | "*.gls", 85 | "*.ist", 86 | "*.fls", 87 | "*.log", 88 | "*.fdb_latexmk", 89 | "*.pdf", 90 | "*.synctex.gz", 91 | "*.xml" 92 | ] 93 | } 94 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # competitive-programming-code-template 2 | 3 | ## 使用方法 4 | 5 | 1. 直接使用编译好的pdf文件 6 | 2. 使用`src`文件夹下的源代码文件 7 | 8 | 若想对模板进行修改,直接修改`head`,`tail`,`main.py`或者源代码文件,后运行`main.py`生成`template.tex`,再编译生成`template.pdf`。其中: 9 | 10 | - `head`:主要是tex的一些配置,如格式,目录等; 11 | - `tail`:补充head。 12 | - `main.py`:根据源代码生成`template.tex`的逻辑。`src`文件夹下,文件夹名为一级标题,文件夹下的源代码为二级标题。没有额外的配置文件,默认将所有源代码都包含进来。 13 | - `template.tex`:生成的tex源码。 14 | - `template.pdf`:生成的pdf文件。 15 | 16 | ## 特性 17 | 18 | 1. 使用了`mathescape`属性,源代码注释中的数学公式会被编译并渲染。 19 | 20 | ## 简介 21 | 22 | - 对于一些复用性较高的算法或者数据结构,需要时再重新实现一次是费时的,如果有一份设计得不错得代码模板,可能会花费更少的时间。 23 | - 在实现实现某个算法时,如果有类似算法的代码作为参考,可能效率会比较高。 24 | - 复习所学内容时,如果将已学内容的实现记录下来的话,可能会有更好的效果。 25 | 26 | 基于以上目的,我自己会实现一些常见算法的代码模板。经过一段时间的完善,自认为写得还行,可能会有参考意义,所以也将这个代码模板开源了。 27 | 28 | 模板既包括源代码文件夹,也包括方便打印的pdf版本。 29 | 30 | 这个模板中更多的是源码和说明性的注释,没有对于原理的解释。如果想要了解原理,百度,Bing,Google,OI Wiki,Luogu甚至B站上,可能会有你想要的东西。 31 | 32 | ## 参考 33 | 34 | 本项目参考了[ACM-ICPC-CodeTemplate-Latex](https://github.com/jasison27/ACM-ICPC-CodeTemplate-Latex)。 35 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import yaml 2 | import os 3 | from subprocess import call 4 | 5 | config_path = './tex/config.yml' 6 | head_path = './tex/head' 7 | tail_path = './tex/tail' 8 | 9 | 10 | def get_head(): 11 | res = "" 12 | with open(head_path, 'r', encoding='utf-8') as f: 13 | lines = f.readlines() 14 | for line in lines: 15 | res += line 16 | return res 17 | 18 | 19 | def get_tail(): 20 | res = "" 21 | with open(tail_path, 'r', encoding='utf-8') as f: 22 | lines = f.readlines() 23 | for line in lines: 24 | res += line 25 | return res 26 | 27 | 28 | def get_code(name, path): 29 | print(f' - add code {name}: {path}') 30 | suf = path.split('.')[1] 31 | path = path 32 | res = '\inputminted[mathescape,linenos,numbersep=5pt,frame=lines,framesep=2mm]' + \ 33 | '{' + suf + '}' + '{' + path + '}' + '\n' 34 | return res 35 | 36 | 37 | def get_subsection(subsection): 38 | print(f' - add subsection{subsection}') 39 | res = "" 40 | 41 | for name in subsection: 42 | res = res + '\\subsection' + '{' + name + '}' + '\n' 43 | path = subsection[name] 44 | res = res + get_code(name, path) 45 | return res 46 | 47 | 48 | def get_section(content, section): 49 | print(f"- add section {section}") 50 | res = '\\section' + '{' + section + '}' + '\n' 51 | for subsection in content[section]: 52 | res = res + get_subsection(subsection) 53 | return res 54 | 55 | 56 | def generate_config(): 57 | sections = os.listdir('src') 58 | print(sections) 59 | 60 | content = {} 61 | for section in sections: 62 | subsections = os.listdir('src/' + section) 63 | print(' ', subsections) 64 | 65 | a = [] 66 | for f in subsections: 67 | name = f.split('.')[0] 68 | path = 'src/' + section + '/' + f 69 | print(' ', name, path) 70 | 71 | a.append({name: path}) 72 | 73 | # code format 74 | if path.endswith('.cpp') or path.endswith('.h'): 75 | path = path.replace('/', "\\") 76 | lc = ['clang-format', '-i', '--style=file', os.getcwd() + '\\' + path] 77 | call(lc) 78 | content[section] = a 79 | config = {'content': content} 80 | 81 | with open('tex/config.yml', 'w') as f: 82 | yaml.safe_dump(config, f) 83 | 84 | return config 85 | 86 | 87 | if __name__ == '__main__': 88 | config = generate_config() 89 | 90 | print(config) 91 | 92 | tex = "" 93 | 94 | tex = tex + get_head() 95 | 96 | content = config['content'] 97 | for section in content: 98 | tex = tex + get_section(content, section) 99 | 100 | tex = tex + get_tail() 101 | 102 | with open('template.tex', 'w', encoding='utf-8') as f: 103 | f.write(tex) 104 | -------------------------------------------------------------------------------- /src/ds/AVLTree.cpp: -------------------------------------------------------------------------------- 1 | // Problem: P6136 【模板】普通平衡树(数据加强版) 2 | // Contest: Luogu 3 | // URL: https://www.luogu.com.cn/problem/P6136 4 | // Memory Limit: 88 MB 5 | // Time Limit: 3000 ms 6 | // 7 | // Powered by CP Editor (https://cpeditor.org) 8 | 9 | #include 10 | 11 | #define CPPIO std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0); 12 | #define freep(p) p ? delete p, p = nullptr, void(1) : void(0) 13 | 14 | #ifdef BACKLIGHT 15 | #include "debug.h" 16 | #else 17 | #define logd(...) ; 18 | #endif 19 | 20 | using i64 = int64_t; 21 | using u64 = uint64_t; 22 | 23 | void solve_case(int Case); 24 | 25 | int main() { 26 | CPPIO; 27 | int T = 1; 28 | // std::cin >> T; 29 | for (int t = 1; t <= T; ++t) { 30 | solve_case(t); 31 | } 32 | return 0; 33 | } 34 | 35 | template 36 | class AVLTree { 37 | private: 38 | struct Node { 39 | ValueType value; 40 | size_t count; 41 | size_t size; 42 | size_t height; 43 | Node* left; 44 | Node* right; 45 | Node() {} 46 | Node(ValueType value) { 47 | this->value = value; 48 | this->count = this->size = 1; 49 | this->height = 1; 50 | this->left = this->right = nullptr; 51 | } 52 | }; 53 | 54 | size_t GetSize(Node* p) { return p ? p->size : 0; } 55 | 56 | size_t GetHeight(Node* p) { return p ? p->height : 0; } 57 | 58 | void Maintain(Node* p) { 59 | if (!p) 60 | return; 61 | p->size = GetSize(p->left) + p->count + GetSize(p->right); 62 | p->height = std::max(GetHeight(p->left), GetHeight(p->right)) + 1; 63 | } 64 | 65 | void Zig(Node*& p) { 66 | Node* r = p->right; 67 | p->right = r->left; 68 | r->left = p; 69 | Maintain(p); 70 | Maintain(r); 71 | p = r; 72 | } 73 | 74 | void Zag(Node*& p) { 75 | Node* l = p->left; 76 | p->left = l->right; 77 | l->right = p; 78 | Maintain(p); 79 | Maintain(l); 80 | p = l; 81 | } 82 | 83 | void KeepBalance(Node*& p) { 84 | if (!p) 85 | return; 86 | if (GetHeight(p->left) - GetHeight(p->right) == -2) { 87 | if (p->right && GetSize(p->right->left) > GetSize(p->right->right)) { 88 | Zag(p->right); 89 | } 90 | Zig(p); 91 | } else if (GetHeight(p->left) - GetHeight(p->right) == 2) { 92 | if (p->left && GetSize(p->left->left) < GetSize(p->left->right)) { 93 | Zig(p->left); 94 | } 95 | Zag(p); 96 | } 97 | Maintain(p); 98 | } 99 | 100 | void InsertInternal(Node*& p, ValueType value) { 101 | if (!p) { 102 | p = new Node(value); 103 | return; 104 | } 105 | if (value < p->value) { 106 | InsertInternal(p->left, value); 107 | } else if (value == p->value) { 108 | p->count++; 109 | } else { 110 | InsertInternal(p->right, value); 111 | } 112 | Maintain(p); 113 | KeepBalance(p); 114 | } 115 | 116 | void DeleteInternal(Node*& p, ValueType value) { 117 | if (!p) 118 | return; 119 | if (value < p->value) { 120 | DeleteInternal(p->left, value); 121 | } else if (value == p->value) { 122 | if (p->left && p->right) { 123 | Node* replace = p->right; 124 | while (replace->left) 125 | replace = replace->left; 126 | p->value = replace->value; 127 | p->count = replace->count; 128 | replace->count = 1; 129 | DeleteInternal(p->right, replace->value); 130 | } else { 131 | Node* temp = p; 132 | if (p->left) 133 | p = p->left; 134 | else if (p->right) 135 | p = p->right; 136 | else 137 | p = nullptr; 138 | freep(temp); 139 | } 140 | } else { 141 | DeleteInternal(p->right, value); 142 | } 143 | Maintain(p); 144 | KeepBalance(p); 145 | } 146 | 147 | void DeleteOneInternal(Node*& p, ValueType value) { 148 | if (!p) 149 | return; 150 | if (value < p->value) { 151 | DeleteOneInternal(p->left, value); 152 | } else if (value == p->value) { 153 | --p->count; 154 | if (p->count == 0) { 155 | if (p->left && p->right) { 156 | Node* replace = p->right; 157 | while (replace->left) 158 | replace = replace->left; 159 | p->value = replace->value; 160 | p->count = replace->count; 161 | replace->count = 1; 162 | DeleteInternal(p->right, replace->value); 163 | } else { 164 | Node* temp = p; 165 | if (p->left) 166 | p = p->left; 167 | else if (p->right) 168 | p = p->right; 169 | else 170 | p = nullptr; 171 | freep(temp); 172 | } 173 | } 174 | } else { 175 | DeleteOneInternal(p->right, value); 176 | } 177 | Maintain(p); 178 | KeepBalance(p); 179 | Maintain(p); 180 | } 181 | 182 | ValueType GetKthInternal(Node* p, size_t k) { 183 | if (k <= 0) 184 | assert(false); 185 | if (k <= GetSize(p->left)) 186 | return GetKthInternal(p->left, k); 187 | else if (k <= GetSize(p->left) + p->count) 188 | return p->value; 189 | else 190 | return GetKthInternal(p->right, k - GetSize(p->left) - p->count); 191 | } 192 | 193 | size_t GetPrevRank(Node* p, ValueType value) { 194 | if (!p) 195 | return 0; 196 | if (value < p->value) { 197 | return GetPrevRank(p->left, value); 198 | } else if (value == p->value) { 199 | return GetSize(p->left); 200 | } else { 201 | return GetSize(p->left) + p->count + GetPrevRank(p->right, value); 202 | } 203 | } 204 | 205 | size_t GetRankInternal(Node* p, ValueType value) { return GetPrevRank(p, value) + 1; } 206 | 207 | size_t GetNextRank(Node* p, ValueType value) { 208 | if (!p) 209 | return 1; 210 | if (value < p->value) { 211 | return GetNextRank(p->left, value); 212 | } else if (value == p->value) { 213 | return GetSize(p->left) + p->count + 1; 214 | } else { 215 | return GetSize(p->left) + p->count + GetNextRank(p->right, value); 216 | } 217 | } 218 | 219 | private: 220 | Node* root_; 221 | 222 | public: 223 | AVLTree() : root_(nullptr) {} 224 | 225 | ~AVLTree() { 226 | std::function dfs = [&](Node* p) -> void { 227 | if (!p) 228 | return; 229 | dfs(p->left); 230 | dfs(p->right); 231 | freep(p); 232 | }; 233 | dfs(root_); 234 | } 235 | 236 | void Insert(ValueType value) { InsertInternal(root_, value); } 237 | 238 | void Delete(ValueType value) { DeleteInternal(root_, value); } 239 | 240 | void DeleteOne(ValueType value) { DeleteOneInternal(root_, value); } 241 | 242 | size_t GetRank(ValueType value) { return GetRankInternal(root_, value); } 243 | 244 | ValueType GetKth(size_t k) { return GetKthInternal(root_, k); } 245 | 246 | ValueType GetPrev(ValueType value) { 247 | size_t prev_rank = GetPrevRank(root_, value); 248 | return GetKthInternal(root_, prev_rank); 249 | } 250 | 251 | ValueType GetNext(ValueType value) { 252 | size_t next_rank = GetNextRank(root_, value); 253 | return GetKthInternal(root_, next_rank); 254 | } 255 | 256 | std::string ToString() { 257 | std::string result; 258 | std::function dfs = [&](Node* p) { 259 | if (!p) 260 | return; 261 | dfs(p->left); 262 | result += "(" + std::to_string(p->value) + "," + std::to_string(p->count) + "), "; 263 | dfs(p->right); 264 | }; 265 | dfs(root_); 266 | return result; 267 | } 268 | }; 269 | 270 | void solve_case(int Case) { 271 | int n, q; 272 | std::cin >> n >> q; 273 | 274 | AVLTree t; 275 | for (int i = 1, x; i <= n; ++i) { 276 | std::cin >> x; 277 | t.Insert(x); 278 | } 279 | 280 | int ans = 0; 281 | for (int i = 1, op, x, last = 0; i <= q; ++i) { 282 | // std::cerr << t.ToString() << std::endl; 283 | std::cin >> op >> x; 284 | x ^= last; 285 | switch (op) { 286 | case 1: 287 | t.Insert(x); 288 | break; 289 | case 2: 290 | t.DeleteOne(x); 291 | break; 292 | case 3: 293 | last = t.GetRank(x); 294 | ans ^= last; 295 | logd(last); 296 | break; 297 | case 4: 298 | last = t.GetKth(x); 299 | ans ^= last; 300 | logd(last); 301 | break; 302 | case 5: 303 | last = t.GetPrev(x); 304 | ans ^= last; 305 | logd(last); 306 | break; 307 | case 6: 308 | last = t.GetNext(x); 309 | ans ^= last; 310 | logd(last); 311 | break; 312 | } 313 | // std::cerr << t.ToString() << std::endl; 314 | } 315 | std::cout << ans << "\n"; 316 | } -------------------------------------------------------------------------------- /src/ds/CDQ.cpp: -------------------------------------------------------------------------------- 1 | // Problem: P3810 【模板】三维偏序(陌上花开) 2 | // Contest: Luogu 3 | // URL: https://www.luogu.com.cn/problem/P3810 4 | // Memory Limit: 500 MB 5 | // Time Limit: 1000 ms 6 | // 7 | // Powered by CP Editor (https://cpeditor.org) 8 | 9 | #include 10 | 11 | #define CPPIO std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0); 12 | #define freep(p) p ? delete p, p = nullptr, void(1) : void(0) 13 | 14 | #ifdef BACKLIGHT 15 | #include "debug.h" 16 | #else 17 | #define logd(...) ; 18 | #define ASSERT(x) ; 19 | #define serialize() "" 20 | #endif 21 | 22 | using i64 = int64_t; 23 | using u64 = uint64_t; 24 | 25 | void Initialize(); 26 | void SolveCase(int Case); 27 | 28 | int main(int argc, char* argv[]) { 29 | CPPIO; 30 | int T = 1; 31 | // std::cin >> T; 32 | for (int t = 1; t <= T; ++t) { 33 | SolveCase(t); 34 | } 35 | return 0; 36 | } 37 | 38 | void Initialize() {} 39 | 40 | template 41 | class FenwickTree { 42 | public: 43 | using Operator = std::function; 44 | 45 | private: 46 | inline int lb(int x) { return x & -x; } 47 | 48 | public: 49 | FenwickTree(int n, const T& init, const Operator& op = std::plus()) 50 | : n_(n), init_(init), c_(n_ + 1, init_), op_(op), t_(n_ + 1, -1), tag_(0) {} 51 | 52 | void Update(int x, T d) { 53 | for (; x <= n_; x += lb(x)) { 54 | if (t_[x] != tag_) 55 | c_[x] = init_; 56 | c_[x] = op_(c_[x], d); 57 | t_[x] = tag_; 58 | } 59 | } 60 | 61 | const T Query(int x) { 62 | T r = init_; 63 | for (; x; x -= lb(x)) { 64 | if (t_[x] == tag_) 65 | r = op_(r, c_[x]); 66 | } 67 | return r; 68 | } 69 | 70 | // TODO(backlight): add something to ensure that this can only be called when op_ is inversable. 71 | const T Query(int l, int r) { return Query(r) - Query(l - 1); } 72 | 73 | // TODO(backlight): similar to range query. 74 | const T Kth(int k) { 75 | T ans = 0, cnt = 0; 76 | for (int i = std::__lg(n_) + 1; i >= 0; --i) { 77 | ans += (1LL << i); 78 | if (ans >= n_ || cnt + c_[ans] >= k) 79 | ans -= (1LL << i); 80 | else 81 | cnt += c_[ans]; 82 | } 83 | return ans + 1; 84 | } 85 | 86 | void Reset() { ++tag_; } 87 | 88 | private: 89 | int n_; 90 | 91 | T init_; 92 | std::vector c_; 93 | const Operator op_; 94 | 95 | std::vector t_; 96 | int tag_; 97 | }; 98 | 99 | void SolveCase(int Case) { 100 | int n, k; 101 | std::cin >> n >> k; 102 | 103 | std::vector> p(n); 104 | for (int i = 0; i < n; ++i) { 105 | int a, b, c; 106 | std::cin >> a >> b >> c; 107 | p[i] = {a, b, c, 1}; 108 | } 109 | std::sort(p.begin(), p.end()); 110 | 111 | int sz = 0; 112 | for (int i = 0; i < n; ++i) { 113 | int cnt = 0; 114 | int j = i; 115 | while (j + 1 < n && p[j + 1] == p[i]) 116 | ++j; 117 | 118 | p[sz++] = {p[i][0], p[i][1], p[i][2], j - i + 1}; 119 | 120 | i = j; 121 | } 122 | p.resize(sz); 123 | 124 | std::vector ans(n, 0); 125 | FenwickTree bit(k, 0); 126 | std::vector> temp(n); 127 | std::function CDQ = [&](int l, int r) { 128 | if (l == r) 129 | return; 130 | 131 | int mid = (l + r) >> 1; 132 | CDQ(l, mid), CDQ(mid + 1, r); 133 | 134 | temp.clear(); 135 | for (int i = l; i <= r; ++i) { 136 | temp.push_back({p[i][1], p[i][2], i, p[i][3]}); 137 | } 138 | std::sort(temp.begin(), temp.end()); 139 | 140 | bit.Reset(); 141 | for (auto [x, y, id, w] : temp) { 142 | if (id <= mid) { 143 | bit.Update(y, w); 144 | } else { 145 | ans[id] += bit.Query(y); 146 | } 147 | } 148 | }; 149 | CDQ(0, n - 1); 150 | 151 | std::vector cnt(n, 0); 152 | for (int i = 0; i < sz; ++i) 153 | cnt[ans[i] + p[i][3] - 1] += p[i][3]; 154 | 155 | for (int i = 0; i < n; ++i) 156 | std::cout << cnt[i] << "\n"; 157 | } 158 | -------------------------------------------------------------------------------- /src/ds/CaptainMo.cpp: -------------------------------------------------------------------------------- 1 | // Captain Mo 2 | // 询问[l, r]内的元素是否互不相同 3 | int Ans, ans[N]; 4 | int block_sz, block_id[N]; 5 | struct Query { 6 | int l, r, id; 7 | Query() {} 8 | Query(int _l, int _r, int _id) 9 | : l(_l), r(_r), id(_id) {} 10 | bool operator<(const Query& q) const { 11 | if (block_id[l] == block_id[q.l]) 12 | return block_id[l] & 1 ? r < q.r : r > q.r; 13 | return block_id[l] < block_id[q.l]; 14 | } 15 | } Q[N]; 16 | 17 | int n, q, a[N]; 18 | 19 | int cnt[N], ge2; 20 | inline void add(int p) { 21 | ++cnt[a[p]]; 22 | if (cnt[a[p]] == 2) 23 | ++ge2; 24 | } 25 | 26 | inline void del(int p) { 27 | if (cnt[a[p]] == 2) 28 | --ge2; 29 | --cnt[a[p]]; 30 | } 31 | 32 | void CaptainMo() { 33 | block_sz = sqrt(n); 34 | for (int i = 1; i <= n; ++i) 35 | block_id[i] = i / block_sz; 36 | sort(Q + 1, Q + 1 + q); 37 | 38 | int l = 1, r = 0; 39 | ge2 = 0; 40 | for (int i = 1; i <= q; ++i) { 41 | while (r < Q[i].r) 42 | ++r, add(r); 43 | while (l < Q[i].l) 44 | del(l), ++l; 45 | while (l > Q[i].l) 46 | --l, add(l); 47 | while (r > Q[i].r) 48 | del(r), --r; 49 | ans[Q[i].id] = (ge2 == 0); 50 | } 51 | } -------------------------------------------------------------------------------- /src/ds/CartesianTree.cpp: -------------------------------------------------------------------------------- 1 | template > 2 | class CartesianTree { 3 | private: 4 | struct TreeNode { 5 | KeyType key_; 6 | ValueType value_; 7 | TreeNode* left_; 8 | TreeNode* right_; 9 | TreeNode() {} 10 | TreeNode(const KeyType& key, 11 | const ValueType& value, 12 | TreeNode* left = nullptr, 13 | TreeNode* right = nullptr) 14 | : key_(key), value_(value), left_(left), right_(right) {} 15 | }; 16 | 17 | private: 18 | TreeNode* AllocateNode(const KeyType& key, const ValueType& value) { 19 | TreeNode* p = new TreeNode(key, value); 20 | return p; 21 | } 22 | 23 | void FreeNode(TreeNode*& p) { 24 | if (p) { 25 | delete p; 26 | p = nullptr; 27 | } 28 | } 29 | 30 | void LeftRotate(TreeNode*& p) { 31 | assert(p->right_ != nullptr); 32 | TreeNode* right = p->right_; 33 | TreeNode* right_left = right->left_; 34 | 35 | p->right_ = right_left; 36 | right->left_ = p; 37 | p = right; 38 | } 39 | 40 | void RightRotate(TreeNode*& p) { 41 | assert(p->left_ != nullptr); 42 | TreeNode* left = p->left_; 43 | TreeNode* left_right = left->right_; 44 | 45 | p->left_ = left_right; 46 | left->right_ = p; 47 | p = left; 48 | } 49 | 50 | void InsertInternal(TreeNode*& p, const KeyType& key, const ValueType& value) { 51 | if (p == nullptr) { 52 | p = AllocateNode(key, value); 53 | return; 54 | } 55 | 56 | if (key <= p->key_) { 57 | InsertInternal(p->left_, key, value); 58 | if (comp_(p->left_->value_, p->value_)) 59 | RightRotate(p); 60 | } else { 61 | InsertInternal(p->right_, key, value); 62 | if (comp_(p->right_->value_, p->value_)) 63 | LeftRotate(p); 64 | } 65 | } 66 | 67 | public: 68 | CartesianTree() : root_(nullptr) {} 69 | 70 | CartesianTree(const std::pair* a, int n) : root_(nullptr) { 71 | std::vector stack; 72 | for (int i = 0; i < n; ++i) { 73 | KeyType key = a[i].first; 74 | ValueType value = a[i].second; 75 | TreeNode* node = AllocateNode(key, value); 76 | while (!stack.empty() && comp_(value, stack.back()->value_)) { 77 | stack.pop_back(); 78 | } 79 | if (!stack.empty()) { 80 | if (stack.back()->right_) { 81 | node->left_ = stack.back()->right_; 82 | } 83 | stack.back()->right_ = node; 84 | } else { 85 | node->left_ = root_; 86 | root_ = node; 87 | } 88 | stack.push_back(node); 89 | } 90 | } 91 | 92 | CartesianTree(const std::vector>& a) : root_(nullptr) { 93 | int n = a.size(); 94 | 95 | std::vector stack; 96 | for (int i = 0; i < n; ++i) { 97 | KeyType key = a[i].first; 98 | ValueType value = a[i].second; 99 | TreeNode* node = AllocateNode(key, value); 100 | while (!stack.empty() && comp_(value, stack.back()->value_)) { 101 | stack.pop_back(); 102 | } 103 | if (!stack.empty()) { 104 | if (stack.back()->right_) { 105 | node->left_ = stack.back()->right_; 106 | } 107 | stack.back()->right_ = node; 108 | } else { 109 | node->left_ = root_; 110 | root_ = node; 111 | } 112 | stack.push_back(node); 113 | } 114 | } 115 | 116 | ~CartesianTree() { 117 | std::queue q; 118 | q.push(root_); 119 | while (!q.empty()) { 120 | TreeNode* p = q.front(); 121 | q.pop(); 122 | 123 | if (p->left_) 124 | q.push(p->left_); 125 | if (p->right_) 126 | q.push(p->right_); 127 | 128 | FreeNode(p); 129 | } 130 | } 131 | 132 | void Insert(const KeyType& key, const ValueType& value) { InsertInternal(root_, key, value); } 133 | 134 | void Solve() { 135 | i64 lans = 0, rans = 0; 136 | 137 | std::queue q; 138 | q.push(root_); 139 | while (!q.empty()) { 140 | TreeNode* p = q.front(); 141 | q.pop(); 142 | 143 | lans ^= (i64(p->key_) * ((p->left_ ? p->left_->key_ : 0) + 1)); 144 | rans ^= (i64(p->key_) * ((p->right_ ? p->right_->key_ : 0) + 1)); 145 | 146 | if (p->left_) 147 | q.push(p->left_); 148 | if (p->right_) 149 | q.push(p->right_); 150 | } 151 | 152 | std::cout << lans << " " << rans << "\n"; 153 | } 154 | 155 | private: 156 | TreeNode* root_; 157 | Comp comp_; 158 | }; -------------------------------------------------------------------------------- /src/ds/DSU.cpp: -------------------------------------------------------------------------------- 1 | class DSU { 2 | public: 3 | DSU(int n) : n_(n), f_(n_) { 4 | for (int i = 0; i < n_; ++i) { 5 | f_[i] = i; 6 | } 7 | } 8 | 9 | int find(int x) { 10 | if (x != f_[x]) 11 | f_[x] = find(f_[x]); 12 | 13 | return f_[x]; 14 | } 15 | 16 | void merge(int x, int y) { 17 | x = find(x), y = find(y); 18 | if (x == y) 19 | return; 20 | 21 | f_[y] = x; 22 | } 23 | 24 | private: 25 | int n_; 26 | std::vector f_; 27 | }; -------------------------------------------------------------------------------- /src/ds/FenwickTree.cpp: -------------------------------------------------------------------------------- 1 | template 2 | class FenwickTree { 3 | public: 4 | using Operator = std::function; 5 | 6 | private: 7 | inline int lb(int x) { return x & -x; } 8 | 9 | public: 10 | FenwickTree(int n, const T& init, const Operator& op = std::plus()) 11 | : n_(n), init_(init), c_(n_ + 1, init_), op_(op), t_(n_ + 1, -1), tag_(0) {} 12 | 13 | void Update(int x, T d) { 14 | for (; x <= n_; x += lb(x)) { 15 | if (t_[x] != tag_) 16 | c_[x] = init_; 17 | c_[x] = op_(c_[x], d); 18 | t_[x] = tag_; 19 | } 20 | } 21 | 22 | const T Query(int x) { 23 | T r = init_; 24 | for (; x; x -= lb(x)) { 25 | if (t_[x] == tag_) 26 | r = op_(r, c_[x]); 27 | } 28 | return r; 29 | } 30 | 31 | // TODO(backlight): add something to ensure that this can only be called when op_ is inversable. 32 | const T Query(int l, int r) { return Query(r) - Query(l - 1); } 33 | 34 | // TODO(backlight): similar to range query. 35 | const T Kth(int k) { 36 | T ans = 0, cnt = 0; 37 | for (int i = std::__lg(n_) + 1; i >= 0; --i) { 38 | ans += (1LL << i); 39 | if (ans >= n_ || cnt + c_[ans] >= k) 40 | ans -= (1LL << i); 41 | else 42 | cnt += c_[ans]; 43 | } 44 | return ans + 1; 45 | } 46 | 47 | void Reset() { ++tag_; } 48 | 49 | private: 50 | int n_; 51 | 52 | T init_; 53 | std::vector c_; 54 | const Operator op_; 55 | 56 | std::vector t_; 57 | int tag_; 58 | }; -------------------------------------------------------------------------------- /src/ds/KDTree.cpp: -------------------------------------------------------------------------------- 1 | // KDTree 2 | // 平面最近点对 3 | template 4 | struct KDTree { 5 | using node = array; 6 | int n; 7 | node p[N], ma[N], mi[N]; 8 | double L[N], R[N], D[N], U[N]; 9 | int sd[N], lc[N], rc[N]; 10 | 11 | KDTree(int _n) 12 | : n(_n) { 13 | } 14 | 15 | double dist(const node& nd1, const node& nd2) { 16 | double res = 0; 17 | for (int j = 0; j < K; ++j) { 18 | res += (nd1[j] - nd2[j]) * (nd1[j] - nd2[j]); 19 | } 20 | return res; 21 | } 22 | 23 | double dist(int x, int y) { 24 | return dist(p[x], p[y]); 25 | } 26 | 27 | double cost(int x, int y) { 28 | double res = 0; 29 | for (int j = 0; j < K; ++j) { 30 | if (mi[y][j] > p[x][j]) 31 | res += (mi[y][j] - p[x][j]) * (mi[y][j] - p[x][j]); 32 | if (ma[y][j] < p[x][j]) 33 | res += (ma[y][j] - p[x][j]) * (ma[y][j] - p[x][j]); 34 | } 35 | return res; 36 | } 37 | 38 | struct cmp { 39 | int s; 40 | cmp(int _s) 41 | : s(_s) { 42 | } 43 | bool operator()(const node& nd1, const node& nd2) const { 44 | return nd1[s] < nd2[s]; 45 | } 46 | }; 47 | 48 | void maintain(int x) { 49 | ma[x] = mi[x] = p[x]; 50 | if (lc[x]) { 51 | for (int j = 0; j < K; ++j) { 52 | ma[x][j] = max(ma[x][j], ma[lc[x]][j]); 53 | mi[x][j] = min(mi[x][j], mi[lc[x]][j]); 54 | } 55 | } 56 | if (rc[x]) { 57 | for (int j = 0; j < K; ++j) { 58 | ma[x][j] = max(ma[x][j], ma[rc[x]][j]); 59 | mi[x][j] = min(mi[x][j], mi[rc[x]][j]); 60 | } 61 | } 62 | } 63 | 64 | int build(int l, int r) { 65 | if (l >= r) 66 | return 0; 67 | int mid = (l + r) >> 1; 68 | 69 | array avg; 70 | for (int i = l; i <= r; ++i) 71 | for (int j = 0; j < K; ++j) 72 | avg[j] += p[i][j]; 73 | for (int j = 0; j < K; ++j) 74 | avg[j] /= (r - l + 1); 75 | 76 | array var; 77 | for (int i = l; i <= r; ++i) 78 | for (int j = 0; j < K; ++j) 79 | var[j] += (p[i][j] - avg[j]) * (p[i][j] - avg[j]); 80 | 81 | sd[mid] = 0; 82 | for (int j = 0; j < K; ++j) 83 | if (var[j] > var[sd[mid]]) 84 | sd[mid] = j; 85 | 86 | nth_element(p + l, p + mid, p + r + 1, cmp(sd[mid])); 87 | 88 | lc[mid] = build(l, mid - 1); 89 | rc[mid] = build(mid + 1, r); 90 | 91 | maintain(mid); 92 | 93 | return mid; 94 | } 95 | 96 | double min_dist; 97 | 98 | void query(int l, int r, int x) { 99 | if (l > r) 100 | return; 101 | int mid = (l + r) >> 1; 102 | if (mid != x) 103 | min_dist = min(min_dist, dist(x, mid)); 104 | if (l == r) 105 | return; 106 | 107 | double dl = cost(x, lc[mid]); 108 | double dr = cost(x, rc[mid]); 109 | 110 | if (dl < min_dist && dr < min_dist) { 111 | if (dl < dr) { 112 | query(l, mid - 1, x); 113 | if (dr < min_dist) 114 | query(mid + 1, r, x); 115 | } else { 116 | query(mid + 1, r, x); 117 | if (dl < min_dist) 118 | query(l, mid - 1, x); 119 | } 120 | } else { 121 | if (dl < min_dist) 122 | query(l, mid - 1, x); 123 | if (dr < min_dist) 124 | query(mid + 1, r, x); 125 | } 126 | } 127 | 128 | double getMindis() { 129 | min_dist = 2e18; 130 | for (int i = 1; i <= n; ++i) 131 | query(1, n, i); 132 | min_dist = sqrt(min_dist); 133 | return min_dist; 134 | } 135 | }; -------------------------------------------------------------------------------- /src/ds/LefitstTree.cpp: -------------------------------------------------------------------------------- 1 | template 2 | struct LeftistForest { 3 | struct LeftistTree { 4 | V v; 5 | int dist; 6 | int l, r, rt; 7 | } t[N]; 8 | LeftistTree& operator[](int x) { return t[x]; } 9 | void init(int n, V* a) { 10 | FOR(i, 1, n) { 11 | t[i].v = a[i]; 12 | t[i].l = t[i].r = t[i].dist = 0; 13 | t[i].rt = i; 14 | } 15 | } 16 | int find(int x) { return t[x].rt == x ? x : t[x].rt = find(t[x].rt); } 17 | int merge(int x, int y) { 18 | if (!x) 19 | return y; 20 | if (!y) 21 | return x; 22 | if (t[x].v > t[y].v) 23 | swap(x, y); // 小根堆 24 | t[x].r = merge(t[x].r, y); 25 | t[t[x].r].rt = x; 26 | if (t[t[x].l].dist < t[t[x].r].dist) 27 | swap(t[x].l, t[x].r); 28 | if (!t[x].r) 29 | t[x].dist = 0; 30 | else 31 | t[x].dist = t[t[x].r].dist + 1; 32 | return x; 33 | } 34 | V top(int x) { 35 | if (t[x].v == -1) 36 | return -1; 37 | x = find(x); 38 | return t[x].v; 39 | } 40 | void pop(int x) { 41 | if (t[x].v == -1) 42 | return; 43 | x = find(x); 44 | t[t[x].l].rt = t[x].l; 45 | t[t[x].r].rt = t[x].r; 46 | t[x].rt = merge(t[x].l, t[x].r); 47 | t[x].v = -1; 48 | } 49 | }; 50 | 51 | int n, m, a[N]; 52 | void solve(int Case) { 53 | rd(n, m); 54 | FOR(i, 1, n) 55 | rd(a[i]); 56 | LeftistForest T; 57 | T.init(n, a); 58 | 59 | int op, x, y; 60 | FOR(_, 1, m) { 61 | rd(op); 62 | debug(op); 63 | if (op == 1) { 64 | rd(x, y); 65 | if (T[x].v == -1 || T[y].v == -1) 66 | continue; 67 | x = T.find(x); 68 | y = T.find(y); 69 | if (x == y) 70 | continue; 71 | T[x].rt = T[y].rt = T.merge(x, y); 72 | } else { 73 | rd(x); 74 | pln(T.top(x)); 75 | T.pop(x); 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /src/ds/PersistentSegmentTree.cpp: -------------------------------------------------------------------------------- 1 | struct PersistentSegmentTree { 2 | // $SIZE = N \log N$ 3 | #define SIZE 200005 * 20 4 | 5 | int tot; 6 | int c[SIZE]; 7 | int L[SIZE], R[SIZE]; 8 | 9 | PersistentSegmentTree() { tot = 0; } 10 | 11 | int update(int rt, int l, int r, int p, int d) { 12 | int nrt = ++tot; 13 | L[nrt] = L[rt]; 14 | R[nrt] = R[rt]; 15 | c[nrt] = c[rt] + d; 16 | 17 | if (l != r) { 18 | int mid = (l + r) >> 1; 19 | if (p <= mid) 20 | L[nrt] = update(L[rt], l, mid, p, d); 21 | else 22 | R[nrt] = update(R[rt], mid + 1, r, p, d); 23 | } 24 | 25 | return nrt; 26 | } 27 | 28 | // 区间第k小 29 | int query(int u, int v, int l, int r, int k) { 30 | if (l == r) 31 | return l; 32 | int left_size = c[L[v]] - c[L[u]]; 33 | int mid = (l + r) >> 1; 34 | if (k <= left_size) 35 | return query(L[u], L[v], l, mid, k); 36 | return query(R[u], R[v], mid + 1, r, k - left_size); 37 | } 38 | }; -------------------------------------------------------------------------------- /src/ds/RMQ.cpp: -------------------------------------------------------------------------------- 1 | template 2 | class RMQ { 3 | private: 4 | using Operator = std::function; 5 | 6 | int n_; 7 | std::vector> a_; 8 | std::vector lg_; 9 | Operator op_; 10 | 11 | public: 12 | RMQ(const std::vector& a, const Operator& op) : op_(op) { 13 | n_ = a.size(); 14 | 15 | lg_.resize(n_ + 1); 16 | lg_[1] = 0; 17 | for (int i = 2; i <= n_; ++i) 18 | lg_[i] = lg_[i >> 1] + 1; 19 | 20 | a_.resize(n_); 21 | for (int i = 0; i < n_; ++i) { 22 | a_[i].resize(lg_[n_] + 1); 23 | a_[i][0] = a[i]; 24 | } 25 | for (int j = 1; j <= lg_[n_]; ++j) { 26 | for (int i = 0; i + (1 << (j - 1)) < n_; ++i) { 27 | a_[i][j] = op_(a_[i][j - 1], a_[i + (1 << (j - 1))][j - 1]); 28 | } 29 | } 30 | } 31 | 32 | const ValueType Query(int l, int r) { 33 | int k = lg_[r - l + 1]; 34 | return op_(a_[l][k], a_[r - (1 << k) + 1][k]); 35 | } 36 | }; -------------------------------------------------------------------------------- /src/ds/RollBackCaptainMo.cpp: -------------------------------------------------------------------------------- 1 | // Roll Back Captain Mo 2 | // 询问[l, r]内值相同的元素的最远距离 3 | int Ans, ans[N]; 4 | int block_sz, block_cnt, block_id[N], L[N], R[N]; 5 | struct Query { 6 | int l, r, id; 7 | Query() {} 8 | Query(int _l, int _r, int _id) 9 | : l(_l), r(_r), id(_id) {} 10 | bool operator<(const Query& q) const { 11 | if (block_id[l] == block_id[q.l]) 12 | return r < q.r; 13 | return block_id[l] < block_id[q.l]; 14 | } 15 | } Q[N]; 16 | 17 | int n, m, q, a[N], b[N]; 18 | 19 | int nums[N], cn; 20 | int mi[N], ma[N]; 21 | int __mi[N]; 22 | 23 | int brute_force(int l, int r) { 24 | int res = 0; 25 | for (int i = l; i <= r; ++i) 26 | __mi[a[i]] = 0; 27 | for (int i = l; i <= r; ++i) { 28 | if (__mi[a[i]]) 29 | res = max(res, i - __mi[a[i]]); 30 | else 31 | __mi[a[i]] = i; 32 | } 33 | return res; 34 | } 35 | 36 | inline void addl(int p) { 37 | if (ma[a[p]]) 38 | Ans = max(Ans, ma[a[p]] - p); 39 | else 40 | ma[a[p]] = p; 41 | } 42 | 43 | inline void addr(int p) { 44 | ma[a[p]] = p; 45 | if (!mi[a[p]]) 46 | mi[a[p]] = p, nums[++cn] = a[p]; 47 | Ans = max(Ans, p - mi[a[p]]); 48 | } 49 | 50 | inline void dell(int p) { 51 | if (ma[a[p]] == p) 52 | ma[a[p]] = 0; 53 | } 54 | 55 | inline void delr(int p) { 56 | } 57 | 58 | inline void clear() { 59 | for (int i = 1; i <= cn; ++i) 60 | mi[nums[i]] = ma[nums[i]] = 0; 61 | } 62 | 63 | void RollBackCaptainMo() { 64 | block_sz = sqrt(n); 65 | block_cnt = n / block_sz; 66 | 67 | for (int i = 1; i <= block_cnt; ++i) 68 | L[i] = R[i - 1] + 1, R[i] = i * block_sz; 69 | if (R[block_cnt] < n) { 70 | ++block_cnt; 71 | L[block_cnt] = R[block_cnt - 1] + 1; 72 | R[block_cnt] = n; 73 | } 74 | 75 | for (int i = 1; i <= block_cnt; ++i) 76 | for (int j = L[i]; j <= R[i]; ++j) 77 | block_id[j] = i; 78 | 79 | sort(Q + 1, Q + 1 + q); 80 | 81 | for (int i = 1, j = 1; j <= block_cnt; ++j) { 82 | int l = R[j] + 1, r = R[j]; 83 | Ans = 0; 84 | cn = 0; 85 | for (; block_id[Q[i].l] == j; ++i) { 86 | if (block_id[Q[i].l] == block_id[Q[i].r]) 87 | ans[Q[i].id] = brute_force(Q[i].l, Q[i].r); 88 | else { 89 | while (r < Q[i].r) 90 | ++r, addr(r); 91 | int tmp = Ans; 92 | while (l > Q[i].l) 93 | --l, addl(l); 94 | ans[Q[i].id] = Ans; 95 | while (l <= R[j]) 96 | dell(l), ++l; 97 | Ans = tmp; 98 | } 99 | } 100 | clear(); 101 | } 102 | } -------------------------------------------------------------------------------- /src/ds/ScapegoatTree.cpp: -------------------------------------------------------------------------------- 1 | template 2 | struct ScapegoatTree { 3 | static constexpr double alpha = 0.75; // alpha \in (0.5, 1) 4 | int root, tot, buf_size; 5 | T v[N]; 6 | int s[N], sz[N], sd[N], cnt[N], l[N], r[N], buf[N]; 7 | 8 | ScapegoatTree() { 9 | root = tot = 0; 10 | } 11 | 12 | int new_node(T _v) { 13 | ++tot; 14 | v[tot] = _v; 15 | s[tot] = sz[tot] = sd[tot] = cnt[tot] = 1; 16 | l[tot] = r[tot] = 0; 17 | return tot; 18 | } 19 | 20 | void push_up(int x) { 21 | if (!x) 22 | return; 23 | int lc = l[x], rc = r[x]; 24 | s[x] = s[lc] + 1 + s[rc]; 25 | sz[x] = sz[lc] + cnt[x] + sz[rc]; 26 | sd[x] = sd[lc] + (cnt[x] != 0) + sd[rc]; 27 | } 28 | 29 | bool balance(int x) { 30 | int lc = l[x], rc = r[x]; 31 | if (alpha * s[x] <= max(s[lc], s[rc])) 32 | return false; 33 | if (alpha * s[x] >= sd[x]) 34 | return false; 35 | return true; 36 | } 37 | 38 | void flatten(int x) { 39 | if (!x) 40 | return; 41 | flatten(l[x]); 42 | if (cnt[x]) 43 | buf[++buf_size] = x; 44 | flatten(r[x]); 45 | } 46 | 47 | void build(int& x, int L, int R) { 48 | if (L > R) { 49 | x = 0; 50 | return; 51 | } 52 | int mid = (L + R) >> 1; 53 | x = buf[mid]; 54 | build(l[x], L, mid - 1); 55 | build(r[x], mid + 1, R); 56 | push_up(x); 57 | } 58 | 59 | void rebuild(int& x) { 60 | buf_size = 0; 61 | flatten(x); 62 | build(x, 1, buf_size); 63 | } 64 | 65 | void ins(int& rt, T val) { 66 | if (!rt) { 67 | rt = new_node(val); 68 | return; 69 | } 70 | if (val == v[rt]) { 71 | ++cnt[rt]; 72 | } else if (val < v[rt]) { 73 | ins(l[rt], val); 74 | } else { 75 | ins(r[rt], val); 76 | } 77 | push_up(rt); 78 | if (!balance(rt)) 79 | rebuild(rt); 80 | } 81 | 82 | void del(int& rt, T val) { 83 | if (!rt) 84 | return; 85 | 86 | if (val == v[rt]) { 87 | if (cnt[rt]) 88 | --cnt[rt]; 89 | } else if (val < v[rt]) { 90 | del(l[rt], val); 91 | } else { 92 | del(r[rt], val); 93 | } 94 | push_up(rt); 95 | if (!balance(rt)) 96 | rebuild(rt); 97 | } 98 | 99 | int getPrevRank(int rt, T val) { 100 | if (!rt) 101 | return 0; 102 | if (v[rt] == val && cnt[rt]) 103 | return sz[l[rt]]; 104 | if (v[rt] < val) 105 | return sz[l[rt]] + cnt[rt] + getPrevRank(r[rt], val); 106 | return getPrevRank(l[rt], val); 107 | } 108 | 109 | int getSuccRank(int rt, T val) { 110 | if (!rt) 111 | return 1; 112 | if (v[rt] == val && cnt[rt]) 113 | return sz[l[rt]] + cnt[rt] + 1; 114 | if (v[rt] < val) 115 | return sz[l[rt]] + cnt[rt] + getSuccRank(r[rt], val); 116 | return getSuccRank(l[rt], val); 117 | } 118 | 119 | T getKth(int rt, int k) { 120 | if (!rt) 121 | return 0; 122 | if (k <= sz[l[rt]]) 123 | return getKth(l[rt], k); 124 | if (k - sz[l[rt]] <= cnt[rt]) 125 | return v[rt]; 126 | return getKth(r[rt], k - sz[l[rt]] - cnt[rt]); 127 | } 128 | 129 | void ins(T val) { 130 | ins(root, val); 131 | } 132 | 133 | void del(T val) { 134 | del(root, val); 135 | } 136 | 137 | int getRank(T val) { 138 | return getPrevRank(root, val) + 1; 139 | } 140 | 141 | T getKth(int k) { 142 | return getKth(root, k); 143 | } 144 | 145 | T getPrev(T val) { 146 | return getKth(getPrevRank(root, val)); 147 | } 148 | 149 | T getSucc(T val) { 150 | return getKth(getSuccRank(root, val)); 151 | } 152 | 153 | void debug(int x) { 154 | if (!x) 155 | return; 156 | debug(l[x]); 157 | cerr << v[x] << " "; 158 | debug(r[x]); 159 | } 160 | 161 | void debug() { 162 | cerr << "ScapegoatTree:" << endl; 163 | debug(root); 164 | cerr << endl; 165 | } 166 | }; -------------------------------------------------------------------------------- /src/ds/SegmentTree.cpp: -------------------------------------------------------------------------------- 1 | template 2 | class SegmentTree { 3 | public: 4 | struct Node { 5 | Node* left_child_; 6 | Node* right_child_; 7 | 8 | int left_bound_; 9 | int right_bound_; 10 | 11 | Data data_; 12 | Tag tag_; 13 | 14 | void ApplayUpdate(const Tag& tag) { 15 | data_.Apply(left_bound_, right_bound_, tag); 16 | tag_.Apply(left_bound_, right_bound_, tag); 17 | } 18 | 19 | void MaintainInfomation() { 20 | ASSERT(left_child_ && right_child_); 21 | 22 | data_ = left_child_->data_ + right_child_->data_; 23 | } 24 | 25 | void Propagation() { 26 | if (tag_.NeedPropagation()) { 27 | right_child_->ApplayUpdate(tag_); 28 | left_child_->ApplayUpdate(tag_); 29 | tag_.Reset(); 30 | } 31 | } 32 | 33 | Node() : left_child_(nullptr), right_child_(nullptr), left_bound_(-1), right_bound_(-1) {} 34 | }; 35 | 36 | /* 37 | * Used for binary search on segment tree. 38 | * 39 | * If it should go to the desire(or optimal) direction, then return ture. Otherwise return false. 40 | * For example, if you want to find the leftmost position satisfying some condition, then return 41 | * true to go left. 42 | */ 43 | using Judger = std::function; 44 | 45 | private: 46 | void UpdateInternal(Node* p, int left, int right, const Tag& tag) { 47 | ASSERT(p); 48 | 49 | if (p->left_bound_ >= left && p->right_bound_ <= right) { 50 | p->ApplayUpdate(tag); 51 | return; 52 | } 53 | 54 | p->Propagation(); 55 | 56 | if (p->left_child_->right_bound_ >= left) 57 | UpdateInternal(p->left_child_, left, right, tag); 58 | if (p->right_child_->left_bound_ <= right) 59 | UpdateInternal(p->right_child_, left, right, tag); 60 | 61 | p->MaintainInfomation(); 62 | } 63 | 64 | const Data QueryInternal(Node* p, int left, int right) { 65 | ASSERT(p); 66 | 67 | if (p->left_bound_ >= left && p->right_bound_ <= right) 68 | return p->data_; 69 | 70 | p->Propagation(); 71 | 72 | Data result; 73 | if (p->left_child_->right_bound_ >= left) 74 | result = result + QueryInternal(p->left_child_, left, right); 75 | if (p->right_child_->left_bound_ <= right) 76 | result = result + QueryInternal(p->right_child_, left, right); 77 | 78 | return result; 79 | } 80 | 81 | std::pair FindLeftmostIfInternal(Node* p, const Judger& judger) { 82 | ASSERT(p); 83 | 84 | if (p->left_bound_ == p->right_bound_) 85 | return {p->left_bound_, p->data_}; 86 | 87 | p->Propagation(); 88 | 89 | if (judger(p->left_child_->data_, p->right_child_->data_)) 90 | return FindLeftmostIfInternal(p->left_child_, judger); 91 | return FindLeftmostIfInternal(p->right_child_, judger); 92 | } 93 | 94 | std::pair FindRightmostIfInternal(Node* p, const Judger& judger) { 95 | ASSERT(p); 96 | 97 | if (p->left_bound_ == p->right_bound_) 98 | return {p->left_bound_, p->data_}; 99 | 100 | p->Propagation(); 101 | 102 | if (judger(p->left_child_->data_, p->right_child_->data_)) 103 | return FindRightmostIfInternal(p->right_child_, judger); 104 | return FindRightmostIfInternal(p->left_child_, judger); 105 | } 106 | 107 | public: 108 | SegmentTree(const std::vector& array) : n_(array.size()) { 109 | std::function build = [&](int left, int right) -> Node* { 110 | Node* p = new Node(); 111 | p->left_bound_ = left; 112 | p->right_bound_ = right; 113 | 114 | if (left == right) { 115 | p->data_ = array[left]; 116 | } else { 117 | int middle = (left + right) >> 1; 118 | p->left_child_ = build(left, middle); 119 | p->right_child_ = build(middle + 1, right); 120 | p->MaintainInfomation(); 121 | } 122 | 123 | return p; 124 | }; 125 | 126 | root_ = build(0, n_ - 1); 127 | } 128 | 129 | ~SegmentTree() { 130 | std::function dfs = [&](Node* p) { 131 | if (!p) 132 | return; 133 | dfs(p->left_child_); 134 | dfs(p->right_child_); 135 | delete p; 136 | }; 137 | 138 | dfs(root_); 139 | } 140 | 141 | void Update(int left, int right, const Tag& tag) { 142 | ASSERT(left >= 0 && right < n_); 143 | 144 | UpdateInternal(root_, left, right, tag); 145 | } 146 | 147 | const Data Query(int left, int right) { 148 | ASSERT(left >= 0 && right < n_); 149 | 150 | return QueryInternal(root_, left, right); 151 | } 152 | 153 | std::pair FindLeftmostIf(const Judger& judger) { 154 | return FindLeftmostIfInternal(root_, judger); 155 | } 156 | 157 | std::pair FindRightmostIf(const Judger& judger) { 158 | return FindRightmostIfInternal(root_, judger); 159 | } 160 | 161 | std::string to_string() const { 162 | std::stringstream ss; 163 | ss << "SegmentTree [\n"; 164 | std::function dfs = [&](Node* p) { 165 | if (p->left_bound_ == p->right_bound_) { 166 | ss << " [" << p->left_bound_ << "]: {" << p->data_.to_string() << "}, {" 167 | << p->tag_.to_string() << "}\n"; 168 | return; 169 | } 170 | dfs(p->left_child_); 171 | dfs(p->right_child_); 172 | }; 173 | dfs(root_); 174 | ss << "]\n\n"; 175 | 176 | return ss.str(); 177 | } 178 | 179 | private: 180 | int n_; 181 | Node* root_; 182 | }; 183 | 184 | struct Tag { 185 | public: 186 | int range_add_; 187 | 188 | public: 189 | Tag(int range_add = 0) : range_add_(range_add) {} 190 | 191 | bool NeedPropagation() { return range_add_ != 0; } 192 | 193 | void Apply(int left, int right, const Tag& tag) { range_add_ = range_add_ + tag.range_add_; } 194 | 195 | void Reset() { range_add_ = 0; } 196 | 197 | std::string to_string() const { return std::to_string(range_add_); } 198 | }; 199 | 200 | struct Data { 201 | public: 202 | int mn1_; 203 | int mn2_; 204 | 205 | public: 206 | Data(int mn1 = 0x3f3f3f3f, int mn2 = 0x3f3f3f3f) : mn1_(mn1), mn2_(mn2) {} 207 | 208 | void Apply(int left, int right, const Tag& tag) { 209 | int length = right - left + 1; 210 | 211 | mn1_ = mn1_ + tag.range_add_; 212 | mn2_ = mn2_ + tag.range_add_; 213 | } 214 | 215 | friend Data operator+(const Data& lhs, const Data& rhs) { 216 | Data result; 217 | 218 | result.mn1_ = std::min(lhs.mn1_, rhs.mn1_); 219 | result.mn2_ = std::min(lhs.mn2_, rhs.mn2_); 220 | 221 | return result; 222 | } 223 | 224 | std::string to_string() const { return std::to_string(mn1_) + ", " + std::to_string(mn2_); } 225 | }; -------------------------------------------------------------------------------- /src/ds/TreapRange.cpp: -------------------------------------------------------------------------------- 1 | // Problem: P3391 【模板】文艺平衡树 2 | // Contest: Luogu 3 | // URL: https://www.luogu.com.cn/problem/P3391 4 | // Memory Limit: 125 MB 5 | // Time Limit: 1000 ms 6 | // 7 | // Powered by CP Editor (https://cpeditor.org) 8 | 9 | #include 10 | 11 | #define CPPIO std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0); 12 | #define freep(p) p ? delete p, p = nullptr, void(1) : void(0) 13 | 14 | #ifdef BACKLIGHT 15 | #include "debug.h" 16 | #else 17 | #define logd(...) ; 18 | #endif 19 | 20 | using i64 = int64_t; 21 | using u64 = uint64_t; 22 | 23 | void solve_case(int Case); 24 | 25 | int main(int argc, char* argv[]) { 26 | CPPIO; 27 | int T = 1; 28 | // std::cin >> T; 29 | for (int t = 1; t <= T; ++t) { 30 | solve_case(t); 31 | } 32 | return 0; 33 | } 34 | 35 | template 36 | class Treap { 37 | private: 38 | typedef int32_t size_t; 39 | 40 | struct Node { 41 | ValueType value; 42 | uint32_t priority; 43 | size_t size; 44 | Node* left; 45 | Node* right; 46 | 47 | int rev; 48 | }; 49 | Node* root_; 50 | std::mt19937 rng_; 51 | 52 | private: 53 | Node* NewNode(ValueType value) { 54 | Node* p = new Node; 55 | p->value = value; 56 | p->priority = rng_(); 57 | p->size = 1; 58 | p->left = p->right = nullptr; 59 | 60 | p->rev = 0; 61 | 62 | return p; 63 | } 64 | 65 | size_t GetSize(Node* p) { return p ? p->size : 0; } 66 | 67 | void PushDown(Node* p) { 68 | if (!p) 69 | return; 70 | if (p->rev) { 71 | std::swap(p->left, p->right); 72 | 73 | if (p->left) 74 | p->left->rev ^= 1; 75 | 76 | if (p->right) 77 | p->right->rev ^= 1; 78 | 79 | p->rev = 0; 80 | } 81 | } 82 | 83 | void PushUp(Node* p) { 84 | if (!p) 85 | return; 86 | p->size = GetSize(p->left) + 1 + GetSize(p->right); 87 | } 88 | 89 | std::pair SplitSize(Node* p, size_t k) { 90 | if (!p) 91 | return {nullptr, nullptr}; 92 | std::pair result; 93 | 94 | PushDown(p); 95 | if (GetSize(p->left) < k) { 96 | auto right_result = SplitSize(p->right, k - GetSize(p->left) - 1); 97 | p->right = right_result.first; 98 | 99 | result.first = p; 100 | result.second = right_result.second; 101 | } else { 102 | auto left_result = SplitSize(p->left, k); 103 | p->left = left_result.second; 104 | 105 | result.first = left_result.first; 106 | result.second = p; 107 | } 108 | PushUp(p); 109 | 110 | return result; 111 | } 112 | 113 | Node* Merge(Node* a, Node* b) { 114 | if (a == nullptr) 115 | return b; 116 | else if (b == nullptr) 117 | return a; 118 | 119 | if (a->priority < b->priority) { 120 | PushDown(a); 121 | a->right = Merge(a->right, b); 122 | PushUp(a); 123 | return a; 124 | } else { 125 | PushDown(b); 126 | b->left = Merge(a, b->left); 127 | PushUp(b); 128 | return b; 129 | } 130 | } 131 | 132 | public: 133 | Treap() : root_(nullptr), rng_(std::chrono::steady_clock::now().time_since_epoch().count()) {} 134 | 135 | ~Treap() { 136 | std::function dfs = [&](Node* p) -> void { 137 | if (!p) 138 | return; 139 | dfs(p->left); 140 | dfs(p->right); 141 | freep(p); 142 | }; 143 | dfs(root_); 144 | } 145 | 146 | void Insert(const size_t& k, ValueType value) { 147 | auto [a, b] = SplitSize(root_, k - 1); 148 | a = Merge(a, NewNode(value)); 149 | root_ = Merge(a, b); 150 | } 151 | 152 | void Delete(const size_t& k) { 153 | auto [a, b] = SplitValue(root_, k); 154 | auto [c, d] = SplitValue(a, k - 1); 155 | 156 | freep(d); 157 | 158 | a = Merge(c, d); 159 | root_ = Merge(a, b); 160 | } 161 | 162 | void Build(const std::vector& a) { 163 | assert(root_ == nullptr); 164 | 165 | std::stack stk; 166 | for (int i = 0; i < (int)a.size(); ++i) { 167 | Node* p = NewNode(a[i]); 168 | Node* last = nullptr; 169 | while (!stk.empty() && stk.top()->priority > p->priority) { 170 | last = stk.top(); 171 | PushUp(last); 172 | stk.pop(); 173 | } 174 | 175 | p->left = last; 176 | if (!stk.empty()) 177 | stk.top()->right = p; 178 | 179 | stk.push(p); 180 | } 181 | 182 | while (!stk.empty()) { 183 | PushUp(stk.top()); 184 | root_ = stk.top(); 185 | stk.pop(); 186 | } 187 | } 188 | 189 | void Reverse(int l, int r) { 190 | auto [a, b] = SplitSize(root_, l - 1); 191 | auto [c, d] = SplitSize(b, r - l + 1); 192 | 193 | c->rev ^= 1; 194 | 195 | b = Merge(c, d); 196 | root_ = Merge(a, b); 197 | } 198 | 199 | std::vector GetPreOrder() { 200 | std::vector a(root_->size); 201 | size_t b = 0; 202 | std::function dfs = [&](Node* p) -> void { 203 | if (!p) 204 | return; 205 | PushDown(p); 206 | dfs(p->left); 207 | a[b++] = p->value; 208 | dfs(p->right); 209 | }; 210 | dfs(root_); 211 | return a; 212 | } 213 | }; 214 | 215 | void solve_case(int Case) { 216 | int n, m; 217 | std::cin >> n >> m; 218 | 219 | std::vector a(n); 220 | for (int i = 0; i < n; ++i) { 221 | a[i] = i + 1; 222 | } 223 | 224 | Treap t; 225 | t.Build(a); 226 | logd(t.GetPreOrder()); 227 | 228 | for (int i = 0, l, r; i < m; ++i) { 229 | std::cin >> l >> r; 230 | logd(l, r); 231 | t.Reverse(l, r); 232 | logd(t.GetPreOrder()); 233 | } 234 | 235 | std::vector b = t.GetPreOrder(); 236 | for (int i = 0; i < n; ++i) 237 | std::cout << b[i] << " \n"[i + 1 == n]; 238 | } -------------------------------------------------------------------------------- /src/ds/TreapValue.cpp: -------------------------------------------------------------------------------- 1 | template 2 | class Treap { 3 | private: 4 | typedef int32_t size_t; 5 | 6 | struct Node { 7 | ValueType value; 8 | uint32_t priority; 9 | size_t size; 10 | Node* left; 11 | Node* right; 12 | }; 13 | Node* root_; 14 | std::mt19937 rng_; 15 | 16 | private: 17 | Node* NewNode(ValueType value) { 18 | Node* p = new Node; 19 | p->value = value; 20 | p->priority = rng_(); 21 | p->size = 1; 22 | p->left = p->right = nullptr; 23 | return p; 24 | } 25 | 26 | void Free(Node*& p) { 27 | if (p) { 28 | delete p; 29 | p = nullptr; 30 | } 31 | } 32 | 33 | size_t GetSize(Node* p) { return p ? p->size : 0; } 34 | 35 | void PushUp(Node* p) { 36 | if (!p) 37 | return; 38 | p->size = GetSize(p->left) + 1 + GetSize(p->right); 39 | } 40 | 41 | std::pair SplitValue(Node* p, const ValueType& value) { 42 | if (!p) 43 | return {nullptr, nullptr}; 44 | 45 | std::pair result; 46 | if (p->value <= value) { 47 | auto right_result = SplitValue(p->right, value); 48 | p->right = right_result.first; 49 | 50 | result.first = p; 51 | result.second = right_result.second; 52 | } else { 53 | auto left_result = SplitValue(p->left, value); 54 | p->left = left_result.second; 55 | 56 | result.first = left_result.first; 57 | result.second = p; 58 | } 59 | PushUp(p); 60 | 61 | return result; 62 | } 63 | 64 | Node* Merge(Node* a, Node* b) { 65 | if (a == nullptr) 66 | return b; 67 | else if (b == nullptr) 68 | return a; 69 | 70 | Node* result; 71 | if (a->priority < b->priority) { 72 | result = a; 73 | a->right = Merge(a->right, b); 74 | PushUp(a); 75 | } else { 76 | result = b; 77 | b->left = Merge(a, b->left); 78 | PushUp(b); 79 | } 80 | 81 | return result; 82 | } 83 | 84 | public: 85 | Treap() : root_(nullptr), rng_(std::chrono::steady_clock::now().time_since_epoch().count()) {} 86 | 87 | ~Treap() { 88 | std::function dfs = [&](Node* p) -> void { 89 | if (!p) 90 | return; 91 | dfs(p->left); 92 | dfs(p->right); 93 | freep(p); 94 | }; 95 | dfs(root_); 96 | } 97 | 98 | void Insert(const ValueType& value) { 99 | auto [a, b] = SplitValue(root_, value); 100 | a = Merge(a, NewNode(value)); 101 | root_ = Merge(a, b); 102 | } 103 | 104 | void Delete(const ValueType& value) { 105 | auto [a, b] = SplitValue(root_, value); 106 | auto [c, d] = SplitValue(a, value - 1); 107 | 108 | assert(d); 109 | 110 | Node* temp = d; 111 | d = Merge(d->left, d->right); 112 | Free(temp); 113 | 114 | a = Merge(c, d); 115 | root_ = Merge(a, b); 116 | } 117 | 118 | size_t GetRank(const ValueType& value) { 119 | auto [a, b] = SplitValue(root_, value - 1); 120 | size_t result = GetSize(a) + 1; 121 | root_ = Merge(a, b); 122 | return result; 123 | } 124 | 125 | ValueType GetKth(size_t k) { 126 | assert(k <= GetSize(root_)); 127 | Node* p = root_; 128 | 129 | ValueType result; 130 | while (p) { 131 | if (k <= GetSize(p->left)) { 132 | p = p->left; 133 | } else if (k == GetSize(p->left) + 1) { 134 | result = p->value; 135 | break; 136 | } else { 137 | k -= GetSize(p->left) + 1; 138 | p = p->right; 139 | } 140 | } 141 | return result; 142 | } 143 | 144 | ValueType GetPrev(const ValueType& value) { 145 | auto [a, b] = SplitValue(root_, value - 1); 146 | 147 | assert(a != nullptr); 148 | Node* c = a; 149 | while (c->right) 150 | c = c->right; 151 | ValueType result = c->value; 152 | 153 | root_ = Merge(a, b); 154 | 155 | return result; 156 | } 157 | 158 | ValueType GetNext(const ValueType& value) { 159 | auto [a, b] = SplitValue(root_, value); 160 | 161 | assert(b != nullptr); 162 | Node* c = b; 163 | while (c->left) 164 | c = c->left; 165 | ValueType result = c->value; 166 | 167 | root_ = Merge(a, b); 168 | 169 | return result; 170 | } 171 | 172 | std::string to_string() const { 173 | std::stringstream ss; 174 | ss << "Treap: ["; 175 | 176 | std::function dfs = [&](Node* p) { 177 | if (p == nullptr) 178 | return; 179 | 180 | dfs(p->left); 181 | ss << serialize(p->value) << ", "; 182 | dfs(p->right); 183 | }; 184 | dfs(root_); 185 | 186 | ss << "]\n"; 187 | 188 | return ss.str(); 189 | } 190 | }; -------------------------------------------------------------------------------- /src/ds/WDSU.cpp: -------------------------------------------------------------------------------- 1 | class WDSU { 2 | public: 3 | WDSU(int n) : n_(n), f_(n_), type_(n_) { 4 | for (int i = 0; i < n_; ++i) { 5 | f_[i] = i; 6 | type_[i] = 0; 7 | } 8 | } 9 | 10 | int find(int x) { 11 | if (x != f_[x]) { 12 | int fx = f_[x]; 13 | int ffx = find(fx); 14 | 15 | f_[x] = ffx; 16 | type_[x] = type_[x] ^ type_[fx]; 17 | } 18 | return f_[x]; 19 | } 20 | 21 | void merge(int x, int y, int z) { 22 | int fx = find(x), fy = find(y); 23 | if (fx == fy) 24 | return; 25 | 26 | f_[fy] = fx; 27 | type_[fy] = type_[x] ^ type_[y] ^ z; 28 | } 29 | 30 | int type(int x) { 31 | int fx = find(x); 32 | return type_[x]; 33 | } 34 | 35 | private: 36 | int n_; 37 | std::vector f_; 38 | std::vector type_; 39 | }; -------------------------------------------------------------------------------- /src/geometry/CloestPair2DLinear.cpp: -------------------------------------------------------------------------------- 1 | // Problem: P7883 平面最近点对(加强加强版) 2 | // Contest: Luogu 3 | // URL: https://www.luogu.com.cn/problem/P7883 4 | // Memory Limit: 512 MB 5 | // Time Limit: 350 ms 6 | // 7 | // Powered by CP Editor (https://cpeditor.org) 8 | #include 9 | using namespace std; 10 | 11 | #define CPPIO ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); 12 | #ifdef BACKLIGHT 13 | #include "debug.h" 14 | #else 15 | #define logd(...) ; 16 | #endif 17 | 18 | using i64 = int64_t; 19 | using u64 = uint64_t; 20 | 21 | void solve_case(int Case); 22 | 23 | int main() { 24 | CPPIO; 25 | int T = 1; 26 | // cin >> T; 27 | for (int t = 1; t <= T; ++t) { 28 | solve_case(t); 29 | } 30 | return 0; 31 | } 32 | 33 | /** 34 | * Solve Cloest Pair Problem in **expected** linear time. 35 | * Idea: https://github.com/OI-wiki/OI-wiki/pull/3851 36 | * */ 37 | template 38 | class ClosestPair2DLinear { 39 | public: 40 | struct Point { 41 | CoordinateType x_; 42 | CoordinateType y_; 43 | 44 | Point() {} 45 | 46 | Point(const CoordinateType& x, const CoordinateType& y) : x_(x), y_(y) {} 47 | 48 | void input() { cin >> x_ >> y_; } 49 | 50 | bool operator==(const Point& p) const { return x_ == p.x_ && y_ == p.y_; } 51 | }; 52 | using PointIt = typename vector::iterator; 53 | using Grid = Point; 54 | 55 | private: 56 | /* FIXME(backlight): find a better solution. */ 57 | /* Ugly hash map. I tried std::unordered_map and get TLE. */ 58 | class GridMap { 59 | public: 60 | static const size_t P = 1'000'000'009LL; 61 | static const size_t M = 1'000'003; 62 | static const size_t npos = numeric_limits::max(); 63 | vector h; 64 | vector nxt; 65 | 66 | void Clear() { 67 | size_t p = npos; 68 | fill(h.begin(), h.end(), p); 69 | } 70 | 71 | size_t GetHash(const Grid& grid) { return (grid.x_ * P + grid.y_) % M; } 72 | 73 | void Insert(size_t index, const Grid& grid) { 74 | size_t hash = GetHash(grid); 75 | nxt[index] = h[hash]; 76 | h[hash] = index; 77 | } 78 | 79 | void Init(size_t n) { 80 | size_t p = npos; 81 | h = vector(M, p); 82 | nxt = vector(n); 83 | } 84 | }; 85 | 86 | private: 87 | PointIt start_; 88 | vector id_; 89 | 90 | CoordinateType grid_length_; 91 | GridMap grid_map_; 92 | 93 | DistanceType result_; 94 | size_t a_; 95 | size_t b_; 96 | 97 | private: 98 | const Point& At(size_t p) const { return *(start_ + p); } 99 | 100 | DistanceType Distance2(const Point& a, const Point& b) const { 101 | DistanceType dx = a.x_ - b.x_; 102 | DistanceType dy = a.y_ - b.y_; 103 | return dx * dx + dy * dy; 104 | } 105 | 106 | Grid CalcGrid(const Point& a) const { 107 | return Grid(a.x_ / grid_length_, a.y_ / grid_length_); 108 | } 109 | 110 | void TryUpdate(size_t a, size_t b) { 111 | DistanceType temp = Distance2(At(a), At(b)); 112 | if (temp < result_) { 113 | result_ = temp; 114 | a_ = a; 115 | b_ = b; 116 | } 117 | } 118 | 119 | void BuildHashTable(size_t size) { 120 | grid_map_.Clear(); 121 | for (size_t i = 0; i < size; ++i) { 122 | const Grid& grid_i = CalcGrid(At(id_[i])); 123 | grid_map_.Insert(id_[i], grid_i); 124 | } 125 | } 126 | 127 | public: 128 | ClosestPair2DLinear() {} 129 | DistanceType Solve(PointIt start, PointIt end) { 130 | size_t length = end - start; 131 | assert(length > 1); 132 | 133 | start_ = start; 134 | id_.resize(length); 135 | iota(id_.begin(), id_.end(), 0); 136 | shuffle(id_.begin(), id_.end(), mt19937(114514)); 137 | grid_map_.Init(length); 138 | 139 | a_ = id_[0]; 140 | b_ = id_[1]; 141 | result_ = Distance2(At(a_), At(b_)); 142 | grid_length_ = sqrt(result_) + 1; 143 | BuildHashTable(2); 144 | 145 | size_t size = 2; 146 | for (size_t i = 2; i < length; ++i) { 147 | DistanceType before_result = result_; 148 | 149 | const Point& cur_point = At(id_[i]); 150 | const Grid& cur_grid = CalcGrid(cur_point); 151 | for (CoordinateType dx = -1; dx <= 1; ++dx) { 152 | for (CoordinateType dy = -1; dy <= 1; ++dy) { 153 | const Grid& next_grid = Grid(cur_grid.x_ + dx, cur_grid.y_ + dy); 154 | size_t hash = grid_map_.GetHash(next_grid); 155 | for (size_t j = grid_map_.h[hash]; j != GridMap::npos; 156 | j = grid_map_.nxt[j]) { 157 | if (next_grid == CalcGrid(At(j))) TryUpdate(id_[i], j); 158 | } 159 | } 160 | } 161 | 162 | if (result_ < before_result) { 163 | grid_length_ = sqrt(result_) + 1; 164 | BuildHashTable(size); 165 | const Grid& new_grid = CalcGrid(cur_point); 166 | grid_map_.Insert(id_[i], new_grid); 167 | } else { 168 | grid_map_.Insert(id_[i], cur_grid); 169 | } 170 | size = size + 1; 171 | } 172 | 173 | return result_; 174 | } 175 | }; 176 | using ClosestPair = ClosestPair2DLinear; 177 | using Point = ClosestPair::Point; 178 | ClosestPair solver; 179 | 180 | void solve_case(int Case) { 181 | int n; 182 | cin >> n; 183 | vector P(n); 184 | for (auto& p : P) p.input(); 185 | 186 | for_each(P.begin(), P.end(), [&](Point& p) { 187 | p.x_ = p.x_ + 1e7; 188 | p.y_ = p.y_ + 1e7; 189 | }); 190 | 191 | i64 ans = solver.Solve(P.begin(), P.end()); 192 | cout << ans << "\n"; 193 | } -------------------------------------------------------------------------------- /src/geometry/ClosestPair2D.cpp: -------------------------------------------------------------------------------- 1 | // Problem: P7883 平面最近点对(加强加强版) 2 | // Contest: Luogu 3 | // URL: https://www.luogu.com.cn/problem/P7883 4 | // Memory Limit: 512 MB 5 | // Time Limit: 350 ms 6 | // 7 | // Powered by CP Editor (https://cpeditor.org) 8 | 9 | #include 10 | using namespace std; 11 | 12 | #define CPPIO ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); 13 | #ifdef BACKLIGHT 14 | #include "debug.h" 15 | #else 16 | #define logd(...) ; 17 | #endif 18 | 19 | using i64 = int64_t; 20 | using u64 = uint64_t; 21 | 22 | void solve_case(int Case); 23 | 24 | int main() { 25 | CPPIO; 26 | int T = 1; 27 | // cin >> T; 28 | for (int t = 1; t <= T; ++t) { 29 | solve_case(t); 30 | } 31 | return 0; 32 | } 33 | 34 | template 35 | class ClosestPair2D { 36 | private: 37 | const static size_t kBruteForceThreshold = 5; 38 | 39 | public: 40 | struct Point { 41 | CoordinateType x_; 42 | CoordinateType y_; 43 | 44 | Point() {} 45 | Point(CoordinateType x, CoordinateType y) : x_(x), y_(y) {} 46 | 47 | void input() { cin >> x_ >> y_; } 48 | }; 49 | 50 | private: 51 | using PointIt = typename vector::iterator; 52 | using It = vector::iterator; 53 | 54 | struct CompX { 55 | ClosestPair2D* p_; 56 | CompX(ClosestPair2D* p) : p_(p) {} 57 | bool operator()(size_t a, size_t b) const { 58 | const Point& pa = p_->At(a); 59 | const Point& pb = p_->At(b); 60 | if (pa.x_ != pb.x_) return pa.x_ < pb.x_; 61 | return pa.y_ < pb.y_; 62 | }; 63 | }; 64 | 65 | struct CompY { 66 | ClosestPair2D* p_; 67 | CompY(ClosestPair2D* p) : p_(p) {} 68 | bool operator()(size_t a, size_t b) const { 69 | const Point& pa = p_->At(a); 70 | const Point& pb = p_->At(b); 71 | return pa.y_ < pb.y_; 72 | }; 73 | }; 74 | 75 | private: 76 | PointIt start_; 77 | vector id_; 78 | vector buffer_; 79 | CompX comp_x_; 80 | CompY comp_y_; 81 | 82 | DistanceType result_; 83 | size_t a_; 84 | size_t b_; 85 | 86 | private: 87 | const Point& At(size_t p) { return *(start_ + p); } 88 | 89 | DistanceType Distance2(const Point& a, const Point& b) { 90 | DistanceType dx = a.x_ - b.x_; 91 | DistanceType dy = a.y_ - b.y_; 92 | return dx * dx + dy * dy; 93 | } 94 | 95 | DistanceType Square(DistanceType x) { return x * x; } 96 | 97 | void TryUpdate(size_t a, size_t b) { 98 | DistanceType temp = Distance2(At(a), At(b)); 99 | if (temp < result_) { 100 | result_ = temp; 101 | a_ = a; 102 | b_ = b; 103 | } 104 | } 105 | 106 | void SolveInternal(It start, It end) { 107 | size_t length = end - start; 108 | if (length <= kBruteForceThreshold) { 109 | for (It i = start; i < end; ++i) { 110 | for (It j = i + 1; j < end; ++j) { 111 | TryUpdate(*i, *j); 112 | } 113 | } 114 | sort(start, end, comp_y_); 115 | return; 116 | } 117 | 118 | It split = start + (length >> 1); 119 | const Point& split_point = At(*split); 120 | SolveInternal(start, split); 121 | SolveInternal(split, end); 122 | 123 | std::inplace_merge(start, split, end, comp_y_); 124 | buffer_.clear(); 125 | for (It i = start; i < end; ++i) { 126 | const Point& cur_point = At(*i); 127 | DistanceType dx2 = Square(cur_point.x_ - split_point.x_); 128 | if (dx2 <= result_) { 129 | for (It j = buffer_.end() - 1; j >= buffer_.begin(); --j) { 130 | const Point& next_point = At(*j); 131 | DistanceType dy2 = Square(next_point.y_ - cur_point.y_); 132 | if (dy2 <= result_) { 133 | TryUpdate(*i, *j); 134 | } else { 135 | break; 136 | } 137 | } 138 | buffer_.push_back(*i); 139 | } 140 | } 141 | } 142 | 143 | public: 144 | ClosestPair2D() : comp_x_(this), comp_y_(this) {} 145 | DistanceType Solve(PointIt start, PointIt end) { 146 | size_t length = end - start; 147 | assert(length > 1); 148 | 149 | start_ = start; 150 | id_.resize(length); 151 | iota(id_.begin(), id_.end(), 0); 152 | sort(id_.begin(), id_.end(), comp_x_); 153 | buffer_.clear(); 154 | buffer_.reserve(length); 155 | 156 | a_ = id_[0]; 157 | b_ = id_[1]; 158 | result_ = Distance2(At(a_), At(b_)); 159 | 160 | SolveInternal(id_.begin(), id_.end()); 161 | 162 | return result_; 163 | } 164 | }; 165 | using ClosestPair = ClosestPair2D; 166 | using Point = ClosestPair::Point; 167 | ClosestPair solver; 168 | 169 | void solve_case(int Case) { 170 | int n; 171 | cin >> n; 172 | vector P(n); 173 | for (auto& p : P) p.input(); 174 | 175 | i64 ans = solver.Solve(P.begin(), P.end()); 176 | cout << ans << "\n"; 177 | } -------------------------------------------------------------------------------- /src/graph/BiGraphMatch.cpp: -------------------------------------------------------------------------------- 1 | // Hopcroft Karp, O(\sqrt{V}E) 2 | struct bigraph { 3 | int dfn; 4 | 5 | vector> G; 6 | 7 | int nl, nr; 8 | vector ml, mr; 9 | vector ll, lr; 10 | vector vis; 11 | 12 | bigraph(int _nl, int _nr) { 13 | nl = _nl; 14 | nr = _nr; 15 | G = vector>(nl + 1); 16 | } 17 | 18 | void addarc(int u, int v) { 19 | G[u].push_back(v); 20 | } 21 | 22 | void addedge(int u, int v) { 23 | G[u].push_back(v); 24 | G[v].push_back(u); 25 | } 26 | 27 | bool bfs() { 28 | queue q; 29 | bool res = false; 30 | 31 | for (int i = 1; i <= nl; ++i) { 32 | if (ml[i]) 33 | ll[i] = 0; 34 | else 35 | ll[i] = 1, q.push(i); 36 | } 37 | 38 | for (int i = 1; i <= nr; ++i) 39 | lr[i] = 0; 40 | 41 | while (!q.empty()) { 42 | int u = q.front(); 43 | q.pop(); 44 | for (int v : G[u]) { 45 | if (lr[v] == 0) { 46 | lr[v] = ll[u] + 1; 47 | if (mr[v]) { 48 | ll[mr[v]] = lr[v] + 1; 49 | q.push(mr[v]); 50 | } else 51 | res = true; 52 | } 53 | } 54 | } 55 | 56 | return res; 57 | }; 58 | 59 | bool dfs(int u) { 60 | for (int v : G[u]) { 61 | if (lr[v] == ll[u] + 1 && vis[v] != dfn) { 62 | vis[v] = dfn; 63 | if (mr[v] == 0 || dfs(mr[v])) { 64 | mr[v] = u; 65 | ml[u] = v; 66 | return true; 67 | } 68 | } 69 | } 70 | return false; 71 | }; 72 | 73 | int HK() { 74 | ml = vector(nl + 1); 75 | mr = vector(nr + 1); 76 | ll = vector(nl + 1); 77 | lr = vector(nr + 1); 78 | vis = vector(nr + 1); 79 | 80 | int res = 0; 81 | while (bfs()) { 82 | ++dfn; 83 | for (int i = 1; i <= nl; ++i) 84 | if (!ml[i]) 85 | res += dfs(i); 86 | } 87 | return res; 88 | } 89 | }; 90 | 91 | /** 92 | * 最小覆盖数 = 最大匹配数 93 | * 最大独立集 = 顶点数 - 二分图匹配数 94 | * DAG 最小路径覆盖数 = 结点数 - 拆点后二分图最大匹配数 95 | */ -------------------------------------------------------------------------------- /src/graph/BiWraphMatch.cpp: -------------------------------------------------------------------------------- 1 | // Kuhn Munkres, O(V^3) 2 | template 3 | struct biwraph { 4 | T TMAX, TMIN; 5 | 6 | int n, nl, nr; 7 | vector> G; 8 | vector highl, highr; 9 | vector slack; 10 | vector matchl, matchr; // match 11 | vector pre; // pre node 12 | vector visl, visr; // vis 13 | vector q; 14 | int ql, qr; 15 | 16 | biwraph(int _nl, int _nr) { 17 | TMAX = numeric_limits::max(); 18 | 19 | nl = _nl; 20 | nr = _nr; 21 | n = max(nl, nr); 22 | G = vector>(n + 1, vector(n + 1)); 23 | highl = vector(n + 1); 24 | highr = vector(n + 1); 25 | slack = vector(n + 1); 26 | matchl = vector(n + 1); 27 | matchr = vector(n + 1); 28 | pre = vector(n + 1); 29 | visl = vector(n + 1); 30 | visr = vector(n + 1); 31 | q = vector(n + 1); 32 | } 33 | 34 | void addarc(int u, int v, T w) { 35 | G[u][v] = max(G[u][v], w); 36 | } 37 | 38 | bool check(int v) { 39 | visr[v] = true; 40 | if (matchr[v]) { 41 | q[qr++] = matchr[v]; 42 | visl[matchr[v]] = true; 43 | return false; 44 | } 45 | 46 | while (v) { 47 | matchr[v] = pre[v]; 48 | swap(v, matchl[pre[v]]); 49 | } 50 | 51 | return true; 52 | } 53 | 54 | void bfs(int now) { 55 | ql = qr = 0; 56 | q[qr++] = now; 57 | visl[now] = 1; 58 | while (true) { 59 | while (ql < qr) { 60 | int u = q[ql++]; 61 | for (int v = 1; v <= n; ++v) { 62 | if (!visr[v]) { 63 | T delta = highl[u] + highr[v] - G[u][v]; 64 | if (slack[v] >= delta) { 65 | pre[v] = u; 66 | if (delta) 67 | slack[v] = delta; 68 | else if (check(v)) 69 | return; 70 | } 71 | } 72 | } 73 | } 74 | 75 | T a = TMAX; 76 | for (int i = 1; i <= n; ++i) 77 | if (!visr[i]) 78 | a = min(a, slack[i]); 79 | for (int i = 1; i <= n; ++i) { 80 | if (visl[i]) 81 | highl[i] -= a; 82 | if (visr[i]) 83 | highr[i] += a; 84 | else 85 | slack[i] -= a; 86 | } 87 | for (int i = 1; i <= n; ++i) 88 | if (!visr[i] && !slack[i] && check(i)) 89 | return; 90 | } 91 | } 92 | 93 | void match() { 94 | fill(highr.begin(), highr.end(), 0); 95 | fill(matchl.begin(), matchl.end(), 0); 96 | fill(matchr.begin(), matchr.end(), 0); 97 | for (int i = 1; i <= n; ++i) 98 | highl[i] = *max_element(G[i].begin() + 1, G[i].end()); 99 | 100 | for (int i = 1; i <= n; ++i) { 101 | fill(slack.begin(), slack.end(), TMAX); 102 | fill(visl.begin(), visl.end(), false); 103 | fill(visr.begin(), visr.end(), false); 104 | bfs(i); 105 | } 106 | } 107 | 108 | T getMaxMatch() { 109 | T res = 0; 110 | match(); 111 | for (int i = 1; i <= n; ++i) { 112 | if (G[i][matchl[i]] > 0) 113 | res += G[i][matchl[i]]; 114 | else 115 | matchl[i] = 0; 116 | } 117 | return res; 118 | } 119 | }; -------------------------------------------------------------------------------- /src/graph/BlockForest.cpp: -------------------------------------------------------------------------------- 1 | // 「APIO2018」铁人两项(https://loj.ac/p/2587) 2 | // 给定一张简单无向图,问有多少对三元组 (s, c, f互不相同)使得存在一条简单路径从 s 出发,经过 c 到达 f 。 3 | #include 4 | using namespace std; 5 | using ll = long long; 6 | const int N = 2e5 + 5; 7 | 8 | int n, m; 9 | int w[N]; 10 | vector G[N], F[N]; 11 | 12 | int cc, scc; 13 | int dfc, dfn[N], low[N]; 14 | int top, stk[N]; 15 | void tarjan(int u) { 16 | ++cc; 17 | dfn[u] = low[u] = ++dfc; 18 | stk[++top] = u; 19 | for (int v : G[u]) { 20 | if (!dfn[v]) { 21 | tarjan(v); 22 | low[u] = min(low[u], low[v]); 23 | if (low[v] == dfn[u]) { 24 | ++scc; 25 | int np = n + scc; 26 | w[np] = 0; 27 | for (int x = 0; x != v; --top) { 28 | x = stk[top]; 29 | F[np].push_back(x); 30 | F[x].push_back(np); 31 | ++w[np]; 32 | } 33 | F[np].push_back(u); 34 | F[u].push_back(np); 35 | ++w[np]; 36 | } 37 | } else 38 | low[u] = min(low[u], dfn[v]); 39 | } 40 | } 41 | 42 | ll ans; 43 | int sz[N]; 44 | void dfs(int u, int fa) { 45 | sz[u] = (u <= n); 46 | for (int v : F[u]) 47 | if (v != fa) { 48 | dfs(v, u); 49 | ans += 2ll * w[u] * sz[u] * sz[v]; 50 | sz[u] += sz[v]; 51 | } 52 | ans += 2ll * w[u] * sz[u] * (cc - sz[u]); 53 | } 54 | 55 | void buildBlockForest() { 56 | for (int i = 1; i <= n; ++i) 57 | if (!dfn[i]) { 58 | cc = 0; 59 | tarjan(i); 60 | --top; 61 | dfs(i, i); 62 | } 63 | } 64 | 65 | void solve(int Case) { 66 | scanf("%d %d", &n, &m); 67 | fill(w + 1, w + 1 + n, -1); 68 | int u, v; 69 | for (int i = 1; i <= m; ++i) { 70 | scanf("%d %d", &u, &v); 71 | G[u].push_back(v); 72 | G[v].push_back(u); 73 | } 74 | buildBlockForest(); 75 | printf("%lld\n", ans); 76 | } 77 | 78 | int main() { 79 | int T = 1; 80 | // scanf("%d", &T); 81 | for (int i = 1; i <= T; ++i) 82 | solve(i); 83 | return 0; 84 | } -------------------------------------------------------------------------------- /src/graph/BlockTree.cpp: -------------------------------------------------------------------------------- 1 | // 树分块:uv之间路径上不同的颜色数(强制在线) 2 | #include 3 | using namespace std; 4 | 5 | const int N = 4e4 + 5; 6 | 7 | int n, m, a[N]; 8 | int nt, t[N]; 9 | 10 | int tot, head[N]; 11 | struct edge { 12 | int v, nxt; 13 | } e[N << 1]; 14 | void init(int n) { 15 | tot = 0; 16 | for (int i = 1; i <= n; ++i) 17 | head[i] = 0; 18 | } 19 | void add(int u, int v) { 20 | ++tot; 21 | e[tot] = (edge){v, head[u]}; 22 | head[u] = tot; 23 | } 24 | #define fore(i, u) for (int i = head[u]; i; i = e[i].nxt) 25 | 26 | int sz[N], son[N], f[N], h[N], top[N]; 27 | 28 | void dfs1(int u, int fa) { 29 | f[u] = fa; 30 | h[u] = h[fa] + 1; 31 | sz[u] = 1; 32 | son[u] = 0; 33 | fore(i, u) { 34 | int v = e[i].v; 35 | if (v == fa) 36 | continue; 37 | dfs1(v, u); 38 | sz[u] += sz[v]; 39 | if (sz[v] > sz[son[u]]) 40 | son[u] = v; 41 | } 42 | } 43 | 44 | void dfs2(int u, int fa, int k) { 45 | top[u] = k; 46 | if (son[u]) 47 | dfs2(son[u], u, k); 48 | fore(i, u) { 49 | int v = e[i].v; 50 | if (v == fa || v == son[u]) 51 | continue; 52 | dfs2(v, u, v); 53 | } 54 | } 55 | 56 | int lca(int u, int v) { 57 | while (top[u] != top[v]) { 58 | if (h[top[u]] < h[top[v]]) 59 | swap(u, v); 60 | u = f[top[u]]; 61 | } 62 | if (h[u] > h[v]) 63 | swap(u, v); 64 | return u; 65 | } 66 | 67 | int dep[N], max_dep[N], pa[N]; 68 | int key_cnt, keyid[N]; 69 | 70 | const int COLORCNT = 4e4 + 2; 71 | const int KEYCNT = 101; 72 | const int gap = 400; 73 | 74 | bitset c[KEYCNT][KEYCNT]; 75 | 76 | int stk[N], tp; 77 | 78 | void dfs_key(int u, int fa) { 79 | dep[u] = dep[fa] + 1; 80 | max_dep[u] = dep[u]; 81 | fore(i, u) { 82 | int v = e[i].v; 83 | if (v == fa) 84 | continue; 85 | dfs_key(v, u); 86 | if (max_dep[v] > max_dep[u]) 87 | max_dep[u] = max_dep[v]; 88 | } 89 | if (max_dep[u] - dep[u] >= gap) { 90 | keyid[u] = ++key_cnt; 91 | max_dep[u] = dep[u]; 92 | } 93 | } 94 | 95 | void dfs_bitset(int u) { 96 | if (keyid[u] && u != stk[tp]) { 97 | for (int x = u; x != stk[tp]; x = f[x]) 98 | c[keyid[stk[tp]]][keyid[u]].set(a[x]); 99 | 100 | for (int i = 1; i < tp; ++i) { 101 | c[keyid[stk[i]]][keyid[u]] = c[keyid[stk[i]]][keyid[stk[tp]]]; 102 | c[keyid[stk[i]]][keyid[u]] |= c[keyid[stk[tp]]][keyid[u]]; 103 | } 104 | pa[u] = stk[tp]; 105 | stk[++tp] = u; 106 | } 107 | for (int i = head[u]; i; i = e[i].nxt) { 108 | if (e[i].v != f[u]) 109 | dfs_bitset(e[i].v); 110 | } 111 | if (keyid[u]) 112 | --tp; 113 | } 114 | 115 | void build_block_tree() { 116 | key_cnt = 0; 117 | dfs_key(1, 1); 118 | if (!keyid[1]) 119 | keyid[1] = ++key_cnt; 120 | 121 | tp = 1; 122 | stk[1] = 1; 123 | dfs_bitset(1); 124 | } 125 | 126 | bitset res; 127 | 128 | int query(int u, int v) { 129 | res.reset(); 130 | int uv = lca(u, v); 131 | 132 | // step 1: jump to nearest key node 133 | while (u != uv && !keyid[u]) { 134 | res.set(a[u]); 135 | u = f[u]; 136 | } 137 | while (v != uv && !keyid[v]) { 138 | res.set(a[v]); 139 | v = f[v]; 140 | } 141 | 142 | // step 2: jump to lowest key node 143 | int pu = u; 144 | while (dep[pa[pu]] >= dep[uv]) 145 | pu = pa[pu]; 146 | if (pu != u) { 147 | res |= c[keyid[pu]][keyid[u]]; 148 | u = pu; 149 | } 150 | 151 | int pv = v; 152 | while (dep[pa[pv]] >= dep[uv]) 153 | pv = pa[pv]; 154 | if (pv != v) { 155 | res |= c[keyid[pv]][keyid[v]]; 156 | v = pv; 157 | } 158 | 159 | // step 3: jump to lca 160 | while (u != uv) { 161 | res.set(a[u]); 162 | u = f[u]; 163 | } 164 | while (v != uv) { 165 | res.set(a[v]); 166 | v = f[v]; 167 | } 168 | 169 | // step 4: set lca 170 | res.set(a[uv]); 171 | 172 | return res.count(); 173 | } 174 | 175 | void solve(int Case) { 176 | scanf("%d %d", &n, &m); 177 | for (int i = 1; i <= n; ++i) { 178 | scanf("%d", &a[i]); 179 | t[i] = a[i]; 180 | } 181 | 182 | sort(t + 1, t + 1 + n); 183 | nt = unique(t + 1, t + 1 + n) - (t + 1); 184 | 185 | for (int i = 1; i <= n; ++i) 186 | a[i] = lower_bound(t + 1, t + 1 + nt, a[i]) - t; 187 | 188 | init(n); 189 | int u, v; 190 | for (int i = 1; i <= n - 1; ++i) { 191 | scanf("%d %d", &u, &v); 192 | add(u, v); 193 | add(v, u); 194 | } 195 | 196 | dfs1(1, 1); 197 | dfs2(1, 1, 1); 198 | 199 | build_block_tree(); 200 | 201 | int lastans = 0; 202 | for (int i = 1; i <= m; ++i) { 203 | scanf("%d %d", &u, &v); 204 | u ^= lastans; 205 | lastans = query(u, v); 206 | printf("%d\n", lastans); 207 | } 208 | } 209 | 210 | int main() { 211 | int T = 1; 212 | // scanf( "%d", &T ); 213 | for (int _ = 1; _ <= T; _++) 214 | solve(_); 215 | return 0; 216 | } -------------------------------------------------------------------------------- /src/graph/Dijkstra.cpp: -------------------------------------------------------------------------------- 1 | template , 3 | typename Edge = std::pair, 4 | typename Node = std::pair> 5 | std::vector Dijkstra(const std::vector>& g, 6 | const std::vector& s) { 7 | const DistanceType INF = std::numeric_limits::max(); 8 | const int n = g.size(); 9 | const Comp comp; 10 | 11 | std::vector dis(n, INF); 12 | std::vector vis(n, false); 13 | 14 | std::priority_queue, Comp> q; 15 | for (int u : s) { 16 | dis[u] = 0; 17 | q.push(Node(dis[u], u)); 18 | } 19 | while (!q.empty()) { 20 | auto [c, u] = q.top(); 21 | q.pop(); 22 | 23 | if (vis[u]) 24 | continue; 25 | vis[u] = true; 26 | 27 | for (auto [w, v] : g[u]) { 28 | if (comp(dis[v], c + w)) { 29 | dis[v] = c + w; 30 | q.push(Node(dis[v], v)); 31 | } 32 | } 33 | } 34 | 35 | return dis; 36 | } -------------------------------------------------------------------------------- /src/graph/EdgeBCC.cpp: -------------------------------------------------------------------------------- 1 | std::vector> EdgeBCC( 2 | int n, 3 | const std::vector>& E) { 4 | int m = E.size(); 5 | 6 | std::vector>> g(n); 7 | for (int i = 0; i < m; ++i) { 8 | auto [u, v] = E[i]; 9 | g[u].push_back({v, 2 * i}); 10 | g[v].push_back({u, 2 * i + 1}); 11 | } 12 | 13 | std::vector is_bridge(m, false); 14 | std::vector> bccs; 15 | std::vector belong(n, -1); 16 | 17 | int dfs_clock = 0; 18 | std::vector dfn(n, -1), low(n); 19 | std::function tarjan = [&](int u, int fa) { 20 | dfn[u] = low[u] = dfs_clock++; 21 | for (auto [v, edge_id] : g[u]) { 22 | if (v == fa) 23 | continue; 24 | 25 | if (dfn[v] == -1) { 26 | tarjan(v, u); 27 | 28 | low[u] = std::min(low[u], low[v]); 29 | 30 | if (dfn[u] < low[v]) { 31 | is_bridge[edge_id / 2] = true; 32 | } 33 | } else if (dfn[v] < dfn[u]) { 34 | low[u] = std::min(low[u], dfn[v]); 35 | } 36 | } 37 | }; 38 | for (int i = 0; i < n; ++i) { 39 | if (dfn[i] == -1) { 40 | tarjan(i, i); 41 | } 42 | } 43 | 44 | std::function blood_fill = [&](int u) { 45 | belong[u] = bccs.size() - 1; 46 | bccs.back().push_back(u); 47 | for (auto [v, edge_id] : g[u]) { 48 | if (is_bridge[edge_id / 2]) 49 | continue; 50 | if (belong[v] != -1) 51 | continue; 52 | blood_fill(v); 53 | } 54 | }; 55 | for (int i = 0; i < n; ++i) { 56 | if (belong[i] == -1) { 57 | bccs.push_back({}); 58 | blood_fill(i); 59 | } 60 | } 61 | 62 | return bccs; 63 | } -------------------------------------------------------------------------------- /src/graph/ExKruskal.cpp: -------------------------------------------------------------------------------- 1 | // https://loj.ac/p/6021 2 | // https://oi-wiki.org/graph/mst/#kruskal_1 3 | #include 4 | using namespace std; 5 | #ifdef BACKLIGHT 6 | #include "debug.h" 7 | #else 8 | #define debug(...) 9 | #endif 10 | 11 | const int __BUFFER_SIZE__ = 1 << 20; 12 | bool NEOF = 1; 13 | int __top; 14 | char __buf[__BUFFER_SIZE__], *__p1 = __buf, *__p2 = __buf, __stk[996]; 15 | inline char nc() { 16 | if (!NEOF) 17 | return EOF; 18 | if (__p1 == __p2) { 19 | __p1 = __buf; 20 | __p2 = __buf + fread(__buf, 1, __BUFFER_SIZE__, stdin); 21 | if (__p1 == __p2) { 22 | NEOF = 0; 23 | return EOF; 24 | } 25 | } 26 | return *__p1++; 27 | } 28 | 29 | template 30 | inline bool rd(T& x) { 31 | char c = nc(); 32 | bool f = 0; 33 | x = 0; 34 | while (!isdigit(c)) 35 | c == '-' && (f = 1), c = nc(); 36 | while (isdigit(c)) 37 | x = x * 10 + (c ^ 48), c = nc(); 38 | if (f) 39 | x = -x; 40 | return NEOF; 41 | } 42 | 43 | typedef unsigned long long ull; 44 | ull myRand(ull& k1, ull& k2) { 45 | ull k3 = k1, k4 = k2; 46 | k1 = k4; 47 | k3 ^= (k3 << 23); 48 | k2 = k3 ^ k4 ^ (k3 >> 17) ^ (k4 >> 26); 49 | return k2 + k4; 50 | } 51 | pair myRanq(ull& k1, ull& k2, int MAXN) { 52 | int x = myRand(k1, k2) % MAXN + 1, y = myRand(k1, k2) % MAXN + 1; 53 | if (x > y) 54 | return make_pair(y, x); 55 | else 56 | return make_pair(x, y); 57 | } 58 | 59 | struct LCAGraph { 60 | int n, m, dfs_clock; 61 | vector> G; 62 | vector dfn, lg, dep; 63 | vector> st; 64 | LCAGraph(int _n = 0) 65 | : n(_n), m(n + n - 1), G(n), dfn(n), lg(m + 1), dep(n), st(m) { 66 | lg[1] = 0; 67 | for (int i = 2; i <= m; ++i) 68 | lg[i] = lg[i >> 1] + 1; 69 | } 70 | void addedge(int u, int v) { G[u].push_back(v); } 71 | void dfs(int u, int fa) { 72 | dfn[u] = dfs_clock; 73 | dep[u] = dep[fa] + 1; 74 | st[dfs_clock][0] = u; 75 | ++dfs_clock; 76 | for (int v : G[u]) { 77 | if (v == fa) 78 | continue; 79 | dfs(v, u); 80 | st[dfs_clock][0] = u; 81 | ++dfs_clock; 82 | } 83 | } 84 | void build(int rt) { 85 | dfs_clock = 0; 86 | int g = lg[m]; 87 | for (int i = 0; i < m; ++i) 88 | st[i].resize(g + 1); 89 | dfs(rt, rt); 90 | for (int j = 1; j <= g; ++j) { 91 | for (int i = 0; i + (1 << (j - 1)) < m; ++i) { 92 | if (dep[st[i][j - 1]] < dep[st[i + (1 << (j - 1))][j - 1]]) 93 | st[i][j] = st[i][j - 1]; 94 | else 95 | st[i][j] = st[i + (1 << (j - 1))][j - 1]; 96 | } 97 | } 98 | } 99 | int query(int u, int v) { 100 | int l = dfn[u], r = dfn[v]; 101 | if (l > r) 102 | swap(l, r); 103 | int g = lg[r - l + 1]; 104 | if (dep[st[l][g]] < dep[st[r - (1 << g) + 1][g]]) 105 | return st[l][g]; 106 | else 107 | return st[r - (1 << g) + 1][g]; 108 | } 109 | }; 110 | 111 | template 112 | struct ExKruskal { 113 | struct Edge { 114 | int u, v; 115 | T w; 116 | Edge() {} 117 | Edge(int _u, int _v, T _w) 118 | : u(_u), v(_v), w(_w) {} 119 | bool operator<(const Edge& e) const { return w < e.w; } 120 | }; 121 | int n, m; 122 | vector E; 123 | vector W; 124 | vector f; 125 | LCAGraph G; 126 | 127 | int find(int x) { return x == f[x] ? x : f[x] = find(f[x]); } 128 | 129 | ExKruskal(int _n = 0) 130 | : n(_n), W(n + n - 1), f(n + n - 1), G(n + n - 1) { 131 | iota(f.begin(), f.end(), 0); 132 | } 133 | 134 | void addedge(int u, int v, T w) { E.emplace_back(u, v, w); } 135 | 136 | void build() { 137 | sort(E.begin(), E.end()); 138 | int id = n - 1, cnt = 0; 139 | for (auto& [u, v, w] : E) { 140 | u = find(u); 141 | v = find(v); 142 | if (u != v) { 143 | ++id; 144 | G.addedge(id, u); 145 | G.addedge(id, v); 146 | f[u] = f[v] = id; 147 | W[id] = w; 148 | ++cnt; 149 | if (cnt == n - 1) 150 | break; 151 | } 152 | } 153 | G.build(id); 154 | } 155 | 156 | int query(int u, int v) { 157 | int lca = G.query(u, v); 158 | return W[lca]; 159 | } 160 | }; 161 | 162 | int n, m, q; 163 | ull a1, a2; 164 | void solve(int Case) { 165 | rd(n), rd(m); 166 | ExKruskal ek(n); 167 | 168 | int u, v, w; 169 | for (int i = 1; i <= m; ++i) { 170 | rd(u), rd(v), rd(w); 171 | --u; 172 | --v; 173 | ek.addedge(u, v, w); 174 | } 175 | 176 | ek.build(); 177 | 178 | rd(q), rd(a1), rd(a2); 179 | 180 | int ans = 0; 181 | for (int i = 1; i <= q; ++i) { 182 | pair p = myRanq(a1, a2, n); 183 | --p.first; 184 | --p.second; 185 | ans ^= ek.query(p.first, p.second); 186 | } 187 | printf("%d\n", ans); 188 | } 189 | 190 | int main() { 191 | #ifdef BACKLIGHT 192 | freopen("a.in", "r", stdin); 193 | #endif 194 | int T = 1; 195 | // cin >> T; 196 | for (int t = 1; t <= T; ++t) 197 | solve(t); 198 | return 0; 199 | } -------------------------------------------------------------------------------- /src/graph/Graph.cpp: -------------------------------------------------------------------------------- 1 | namespace Backlight { 2 | 3 | struct Graph { 4 | struct Edge { 5 | int u, v; 6 | Edge() {} 7 | Edge(int _u, int _v) 8 | : u(_u), v(_v) {} 9 | }; 10 | 11 | int V; 12 | vector> G; 13 | 14 | Graph() 15 | : V(0) {} 16 | Graph(int _V) 17 | : V(_V), G(_V + 1) {} 18 | 19 | inline void addarc(int u, int v) { 20 | assert(1 <= u && u <= V); 21 | assert(1 <= v && v <= V); 22 | G[u].push_back(Edge(u, v)); 23 | } 24 | 25 | inline void addedge(int u, int v) { 26 | addarc(u, v); 27 | addarc(v, u); 28 | } 29 | }; 30 | 31 | } // namespace Backlight -------------------------------------------------------------------------------- /src/graph/GraphMatch.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // graph 5 | template 6 | class graph { 7 | public: 8 | struct edge { 9 | int from; 10 | int to; 11 | T cost; 12 | }; 13 | vector edges; 14 | vector> g; 15 | int n; 16 | graph(int _n) 17 | : n(_n) { 18 | g.resize(n); 19 | } 20 | virtual int add(int from, int to, T cost) = 0; 21 | }; 22 | 23 | // undirectedgraph 24 | template 25 | class undirectedgraph : public graph { 26 | public: 27 | using graph::edges; 28 | using graph::g; 29 | using graph::n; 30 | 31 | undirectedgraph(int _n) 32 | : graph(_n) { 33 | } 34 | int add(int from, int to, T cost = 1) { 35 | assert(0 <= from && from < n && 0 <= to && to < n); 36 | int id = (int)edges.size(); 37 | g[from].push_back(id); 38 | g[to].push_back(id); 39 | edges.push_back({from, to, cost}); 40 | return id; 41 | } 42 | }; 43 | 44 | // blossom / find_max_unweighted_matching 45 | template 46 | vector find_max_unweighted_matching(const undirectedgraph& g) { 47 | std::mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 48 | vector match(g.n, -1); // 匹配 49 | vector aux(g.n, -1); // 时间戳记 50 | vector label(g.n); // "o" or "i" 51 | vector orig(g.n); // 花根 52 | vector parent(g.n, -1); // 父节点 53 | queue q; 54 | int aux_time = -1; 55 | 56 | auto lca = [&](int v, int u) { 57 | aux_time++; 58 | while (true) { 59 | if (v != -1) { 60 | if (aux[v] == aux_time) { // 找到拜访过的点 也就是LCA 61 | return v; 62 | } 63 | aux[v] = aux_time; 64 | if (match[v] == -1) { 65 | v = -1; 66 | } else { 67 | v = orig[parent[match[v]]]; // 以匹配点的父节点继续寻找 68 | } 69 | } 70 | swap(v, u); 71 | } 72 | }; // lca 73 | 74 | auto blossom = [&](int v, int u, int a) { 75 | while (orig[v] != a) { 76 | parent[v] = u; 77 | u = match[v]; 78 | if (label[u] == 1) { // 初始点设为"o" 找增广路 79 | label[u] = 0; 80 | q.push(u); 81 | } 82 | orig[v] = orig[u] = a; // 缩花 83 | v = parent[u]; 84 | } 85 | }; // blossom 86 | 87 | auto augment = [&](int v) { 88 | while (v != -1) { 89 | int pv = parent[v]; 90 | int next_v = match[pv]; 91 | match[v] = pv; 92 | match[pv] = v; 93 | v = next_v; 94 | } 95 | }; // augment 96 | 97 | auto bfs = [&](int root) { 98 | fill(label.begin(), label.end(), -1); 99 | iota(orig.begin(), orig.end(), 0); 100 | while (!q.empty()) { 101 | q.pop(); 102 | } 103 | q.push(root); 104 | // 初始点设为 "o", 这里以"0"代替"o", "1"代替"i" 105 | label[root] = 0; 106 | while (!q.empty()) { 107 | int v = q.front(); 108 | q.pop(); 109 | for (int id : g.g[v]) { 110 | auto& e = g.edges[id]; 111 | int u = e.from ^ e.to ^ v; 112 | if (label[u] == -1) { // 找到未拜访点 113 | label[u] = 1; // 标记 "i" 114 | parent[u] = v; 115 | if (match[u] == -1) { // 找到未匹配点 116 | augment(u); // 寻找增广路径 117 | return true; 118 | } 119 | // 找到已匹配点 将与她匹配的点丢入queue 延伸交错树 120 | label[match[u]] = 0; 121 | q.push(match[u]); 122 | continue; 123 | } else if (label[u] == 0 && orig[v] != orig[u]) { // 找到已拜访点 且标记同为"o" 代表找到"花" 124 | int a = lca(orig[v], orig[u]); 125 | // 找LCA 然后缩花 126 | blossom(u, v, a); 127 | blossom(v, u, a); 128 | } 129 | } 130 | } 131 | return false; 132 | }; // bfs 133 | 134 | auto greedy = [&]() { 135 | vector order(g.n); 136 | // 随机打乱 order 137 | iota(order.begin(), order.end(), 0); 138 | shuffle(order.begin(), order.end(), rng); 139 | 140 | // 将可以匹配的点匹配 141 | for (int i : order) { 142 | if (match[i] == -1) { 143 | for (auto id : g.g[i]) { 144 | auto& e = g.edges[id]; 145 | int to = e.from ^ e.to ^ i; 146 | if (match[to] == -1) { 147 | match[i] = to; 148 | match[to] = i; 149 | break; 150 | } 151 | } 152 | } 153 | } 154 | }; // greedy 155 | 156 | // 一开始先随机匹配 157 | greedy(); 158 | // 对未匹配点找增广路 159 | for (int i = 0; i < g.n; i++) { 160 | if (match[i] == -1) { 161 | bfs(i); 162 | } 163 | } 164 | return match; 165 | } 166 | int main() { 167 | ios::sync_with_stdio(0), cin.tie(0); 168 | int n, m; 169 | cin >> n >> m; 170 | undirectedgraph g(n); 171 | int u, v; 172 | for (int i = 0; i < m; i++) { 173 | cin >> u >> v; 174 | u--; 175 | v--; 176 | g.add(u, v, 1); 177 | } 178 | auto blossom_match = find_max_unweighted_matching(g); 179 | vector ans; 180 | int tot = 0; 181 | for (int i = 0; i < blossom_match.size(); i++) { 182 | ans.push_back(blossom_match[i]); 183 | if (blossom_match[i] != -1) { 184 | tot++; 185 | } 186 | } 187 | cout << (tot >> 1) << "\n"; 188 | for (auto x : ans) { 189 | cout << x + 1 << " "; 190 | } 191 | } -------------------------------------------------------------------------------- /src/graph/HLD-Edge.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | const int N = 2e5 + 5; 5 | 6 | int n, q; 7 | 8 | struct edge { 9 | int v, w, nxt; 10 | } e[N << 1]; 11 | int tot, head[N]; 12 | void init_graph(int n) { 13 | tot = 0; 14 | fill(head + 1, head + 1 + n, 0); 15 | } 16 | void add(int u, int v, int w) { 17 | ++tot; 18 | e[tot] = (edge){v, w, head[u]}; 19 | head[u] = tot; 20 | } 21 | 22 | int sz[N], son[N], h[N], f[N], w[N]; 23 | void dfs1(int u, int fa) { 24 | h[u] = h[fa] + 1; 25 | f[u] = fa; 26 | sz[u] = 1; 27 | son[u] = 0; 28 | for (int i = head[u]; i; i = e[i].nxt) { 29 | int v = e[i].v; 30 | if (v == fa) 31 | continue; 32 | w[v] = e[i].w; 33 | dfs1(v, u); 34 | sz[u] += sz[v]; 35 | if (sz[v] > sz[son[u]]) 36 | son[u] = v; 37 | } 38 | } 39 | int dfs_clock, dfn[N], rk[N], top[N]; 40 | void dfs2(int u, int fa, int tp) { 41 | ++dfs_clock; 42 | dfn[dfs_clock] = w[u]; 43 | rk[u] = dfs_clock; 44 | top[u] = tp; 45 | if (son[u]) 46 | dfs2(son[u], u, tp); 47 | for (int i = head[u]; i; i = e[i].nxt) { 48 | int v = e[i].v; 49 | if (v == fa || v == son[u]) 50 | continue; 51 | dfs2(v, u, v); 52 | } 53 | } 54 | 55 | #define mid ((l + r) >> 1) 56 | #define lc (x << 1) 57 | #define rc (x << 1 | 1) 58 | #define lson lc, l, mid 59 | #define rson rc, mid + 1, r 60 | int sum[N << 2], ma[N << 2], mi[N << 2], tag_inv[N << 2]; 61 | void push_up(int x) { 62 | sum[x] = sum[lc] + sum[rc]; 63 | ma[x] = max(ma[lc], ma[rc]); 64 | mi[x] = min(mi[lc], mi[rc]); 65 | } 66 | void push_down(int x) { 67 | if (tag_inv[x] != 1) { 68 | sum[lc] = -sum[lc]; 69 | swap(ma[lc], mi[lc]); 70 | ma[lc] = -ma[lc]; 71 | mi[lc] = -mi[lc]; 72 | tag_inv[lc] = -tag_inv[lc]; 73 | 74 | sum[rc] = -sum[rc]; 75 | swap(ma[rc], mi[rc]); 76 | ma[rc] = -ma[rc]; 77 | mi[rc] = -mi[rc]; 78 | tag_inv[rc] = -tag_inv[rc]; 79 | 80 | tag_inv[x] = 1; 81 | } 82 | } 83 | void build(int x, int l, int r) { 84 | tag_inv[x] = 1; 85 | if (l == r) { 86 | sum[x] = ma[x] = mi[x] = dfn[l]; 87 | return; 88 | } 89 | build(lson); 90 | build(rson); 91 | push_up(x); 92 | } 93 | 94 | void update(int x, int l, int r, int p, int w) { 95 | if (l == r) { 96 | sum[x] = ma[x] = mi[x] = w; 97 | return; 98 | } 99 | push_down(x); 100 | if (p <= mid) 101 | update(lson, p, w); 102 | else 103 | update(rson, p, w); 104 | push_up(x); 105 | } 106 | 107 | void inverse(int x, int l, int r, int L, int R) { 108 | if (l == L && r == R) { 109 | sum[x] = -sum[x]; 110 | swap(ma[x], mi[x]); 111 | ma[x] = -ma[x]; 112 | mi[x] = -mi[x]; 113 | tag_inv[x] = -tag_inv[x]; 114 | return; 115 | } 116 | push_down(x); 117 | if (R <= mid) 118 | inverse(lson, L, R); 119 | else if (L > mid) 120 | inverse(rson, L, R); 121 | else { 122 | inverse(lson, L, mid); 123 | inverse(rson, mid + 1, R); 124 | } 125 | push_up(x); 126 | } 127 | 128 | int getsum(int x, int l, int r, int L, int R) { 129 | if (l == L && r == R) 130 | return sum[x]; 131 | push_down(x); 132 | if (R <= mid) 133 | return getsum(lson, L, R); 134 | else if (L > mid) 135 | return getsum(rson, L, R); 136 | return getsum(lson, L, mid) + getsum(rson, mid + 1, R); 137 | } 138 | 139 | int getmax(int x, int l, int r, int L, int R) { 140 | if (l == L && r == R) 141 | return ma[x]; 142 | push_down(x); 143 | if (R <= mid) 144 | return getmax(lson, L, R); 145 | else if (L > mid) 146 | return getmax(rson, L, R); 147 | return max(getmax(lson, L, mid), getmax(rson, mid + 1, R)); 148 | } 149 | 150 | int getmin(int x, int l, int r, int L, int R) { 151 | if (l == L && r == R) 152 | return mi[x]; 153 | push_down(x); 154 | if (R <= mid) 155 | return getmin(lson, L, R); 156 | else if (L > mid) 157 | return getmin(rson, L, R); 158 | return min(getmin(lson, L, mid), getmin(rson, mid + 1, R)); 159 | } 160 | 161 | void INVERSE(int u, int v) { 162 | while (top[u] != top[v]) { 163 | if (h[top[u]] < h[top[v]]) 164 | swap(u, v); 165 | inverse(1, 1, n, rk[top[u]], rk[u]); 166 | u = f[top[u]]; 167 | } 168 | if (h[u] != h[v]) { 169 | if (h[u] > h[v]) 170 | swap(u, v); 171 | inverse(1, 1, n, rk[son[u]], rk[v]); 172 | } 173 | } 174 | 175 | int QSUM(int u, int v) { 176 | int res = 0; 177 | while (top[u] != top[v]) { 178 | if (h[top[u]] < h[top[v]]) 179 | swap(u, v); 180 | res += getsum(1, 1, n, rk[top[u]], rk[u]); 181 | u = f[top[u]]; 182 | } 183 | if (h[u] != h[v]) { 184 | if (h[u] > h[v]) 185 | swap(u, v); 186 | res += getsum(1, 1, n, rk[son[u]], rk[v]); 187 | } 188 | return res; 189 | } 190 | 191 | int QMAX(int u, int v) { 192 | int res = INT_MIN; 193 | while (top[u] != top[v]) { 194 | if (h[top[u]] < h[top[v]]) 195 | swap(u, v); 196 | res = max(res, getmax(1, 1, n, rk[top[u]], rk[u])); 197 | u = f[top[u]]; 198 | } 199 | if (h[u] != h[v]) { 200 | if (h[u] > h[v]) 201 | swap(u, v); 202 | res = max(res, getmax(1, 1, n, rk[son[u]], rk[v])); 203 | } 204 | return res; 205 | } 206 | 207 | int QMIN(int u, int v) { 208 | int res = INT_MAX; 209 | while (top[u] != top[v]) { 210 | if (h[top[u]] < h[top[v]]) 211 | swap(u, v); 212 | res = min(res, getmin(1, 1, n, rk[top[u]], rk[u])); 213 | u = f[top[u]]; 214 | } 215 | if (h[u] != h[v]) { 216 | if (h[u] > h[v]) 217 | swap(u, v); 218 | res = min(res, getmin(1, 1, n, rk[son[u]], rk[v])); 219 | } 220 | return res; 221 | } 222 | 223 | int tu[N], tv[N]; 224 | void solve(int Case) { 225 | /* write code here */ 226 | /* gl & hf */ 227 | scanf("%d", &n); 228 | int u, v, w; 229 | for (int i = 1; i <= n - 1; ++i) { 230 | scanf("%d %d %d", &u, &v, &w); 231 | ++u, ++v; 232 | add(u, v, w); 233 | add(v, u, w); 234 | 235 | tu[i] = u; 236 | tv[i] = v; 237 | } 238 | 239 | dfs1(1, 1); 240 | dfs2(1, 1, 1); 241 | 242 | build(1, 1, n); 243 | 244 | scanf("%d", &q); 245 | char op[5]; 246 | int x, y; 247 | for (int i = 1; i <= q; ++i) { 248 | scanf("%s %d %d", op, &x, &y); 249 | ++x, ++y; 250 | if (op[0] == 'C') { 251 | --x, --y; 252 | int id = h[tu[x]] > h[tv[x]] ? tu[x] : tv[x]; 253 | update(1, 1, n, rk[id], y); 254 | } else if (op[0] == 'N') { 255 | INVERSE(x, y); 256 | } else if (op[0] == 'S') { 257 | printf("%d\n", QSUM(x, y)); 258 | } else if (op[1] == 'A') { 259 | printf("%d\n", QMAX(x, y)); 260 | } else if (op[1] == 'I') { 261 | printf("%d\n", QMIN(x, y)); 262 | } 263 | } 264 | } 265 | 266 | int main() { 267 | int T = 1; 268 | for (int _ = 1; _ <= T; _++) 269 | solve(_); 270 | return 0; 271 | } -------------------------------------------------------------------------------- /src/graph/KosarajuSCC.cpp: -------------------------------------------------------------------------------- 1 | std::vector> KosarajuSCC(const std::vector>& g) { 2 | int n = g.size(); 3 | std::vector> r(n); 4 | for (int u = 0; u < n; ++u) { 5 | for (int v : g[u]) { 6 | r[v].push_back(u); 7 | } 8 | } 9 | 10 | int dfs_clock = 0; 11 | std::vector vis(n, false); 12 | std::vector dfn(n, -1); 13 | std::function dfs1 = [&](int u) { 14 | vis[u] = true; 15 | for (const int& v : g[u]) { 16 | if (!vis[v]) 17 | dfs1(v); 18 | } 19 | dfn[dfs_clock++] = u; 20 | }; 21 | for (int i = 0; i < n; ++i) { 22 | if (!vis[i]) 23 | dfs1(i); 24 | } 25 | 26 | int scc_count = 0; 27 | std::vector> sccs; 28 | std::vector belong(n, -1); 29 | std::function dfs2 = [&](int u) { 30 | belong[u] = scc_count - 1; 31 | sccs[scc_count - 1].push_back(u); 32 | for (const int& v : r[u]) { 33 | if (belong[v] == -1) 34 | dfs2(v); 35 | } 36 | }; 37 | for (int i = n - 1; i >= 0; --i) { 38 | if (belong[dfn[i]] == -1) { 39 | ++scc_count; 40 | sccs.push_back({}); 41 | dfs2(dfn[i]); 42 | } 43 | } 44 | 45 | return sccs; 46 | } -------------------------------------------------------------------------------- /src/graph/Kruskal.cpp: -------------------------------------------------------------------------------- 1 | namespace Backlight { 2 | 3 | template 4 | struct Wraph { 5 | struct Edge { 6 | int u, v; 7 | T w; 8 | Edge() {} 9 | Edge(int _u, int _v, T _w) 10 | : u(_u), v(_v), w(_w) {} 11 | bool operator<(const Edge& e) { 12 | return w < e.w; 13 | } 14 | }; 15 | 16 | int V; 17 | vector> G; 18 | vector E; 19 | 20 | Wraph() 21 | : V(0) {} 22 | Wraph(int _V) 23 | : V(_V), G(_V + 1) {} 24 | 25 | inline void addarc(int u, int v, T w) { 26 | assert(1 <= u && u <= V); 27 | assert(1 <= v && v <= V); 28 | G[u].push_back(Edge(u, v, w)); 29 | E.push_back(Edge(u, v, w)); 30 | } 31 | 32 | inline void addedge(int u, int v, T w) { 33 | addarc(u, v, w); 34 | addarc(v, u, w); 35 | } 36 | 37 | /**************************************************/ 38 | T kruskal() { 39 | vector fa(V + 1); 40 | for (int i = 1; i <= V; ++i) 41 | fa[i] = i; 42 | 43 | auto find = [&fa](auto self, int x) { 44 | if (x == fa[x]) 45 | return x; 46 | fa[x] = self(self, fa[x]); 47 | return fa[x]; 48 | }; 49 | 50 | auto merge = [&fa, find](int x, int y) { 51 | x = find(find, x); 52 | y = find(find, y); 53 | if (x == y) 54 | return false; 55 | fa[x] = y; 56 | return true; 57 | }; 58 | 59 | T cost = 0; 60 | int cnt = 0; 61 | sort(E.begin(), E.end()); 62 | for (int i = 0; i < (int)E.size(); ++i) { 63 | Edge e = E[i]; 64 | if (merge(e.u, e.v)) { 65 | cost = e.w; 66 | ++cnt; 67 | if (cnt == V - 1) 68 | break; 69 | } 70 | } 71 | return cost; 72 | } 73 | }; 74 | 75 | } // namespace Backlight -------------------------------------------------------------------------------- /src/graph/LCA-HLD.cpp: -------------------------------------------------------------------------------- 1 | class LCA { 2 | private: 3 | int n_; 4 | const std::vector>& g_; 5 | std::vector f, sz, son, dep, top; 6 | 7 | void dfs1(int u, int fa) { 8 | f[u] = fa; 9 | sz[u] = 1; 10 | son[u] = -1; 11 | for (int v : g_[u]) { 12 | if (v == fa) 13 | continue; 14 | dep[v] = dep[u] + 1; 15 | dfs1(v, u); 16 | sz[u] += sz[v]; 17 | if (son[u] == -1 || sz[v] > sz[son[u]]) 18 | son[u] = v; 19 | } 20 | } 21 | 22 | void dfs2(int u, int fa, int tp) { 23 | top[u] = tp; 24 | if (son[u] != -1) 25 | dfs2(son[u], u, tp); 26 | for (int v : g_[u]) { 27 | if (v == fa || v == son[u]) 28 | continue; 29 | dfs2(v, u, v); 30 | } 31 | } 32 | 33 | public: 34 | LCA(const std::vector>& g) : n_(g.size()), g_(g) { 35 | dep.resize(n_); 36 | f.resize(n_); 37 | sz.resize(n_); 38 | son.resize(n_); 39 | top.resize(n_); 40 | 41 | dep[0] = 0; 42 | dfs1(0, 0); 43 | dfs2(0, 0, 0); 44 | } 45 | 46 | int lca(int u, int v) { 47 | while (top[u] != top[v]) { 48 | if (dep[top[u]] < dep[top[v]]) 49 | std::swap(u, v); 50 | u = f[top[u]]; 51 | } 52 | if (dep[u] > dep[v]) 53 | std::swap(u, v); 54 | return u; 55 | } 56 | }; -------------------------------------------------------------------------------- /src/graph/LCA.cpp: -------------------------------------------------------------------------------- 1 | namespace Backlight { 2 | 3 | template 4 | struct Wraph { 5 | struct Edge { 6 | int u, v; 7 | T w; 8 | Edge() {} 9 | Edge(int _u, int _v, T _w) 10 | : u(_u), v(_v), w(_w) {} 11 | }; 12 | 13 | int V; 14 | vector> G; 15 | 16 | Wraph() 17 | : V(0) {} 18 | Wraph(int _V) 19 | : V(_V), G(_V + 1) {} 20 | 21 | inline void addarc(int u, int v, T w = 1) { 22 | assert(1 <= u && u <= V); 23 | assert(1 <= v && v <= V); 24 | G[u].push_back(Edge(u, v, w)); 25 | } 26 | 27 | inline void addedge(int u, int v, T w = 1) { 28 | addarc(u, v, w); 29 | addarc(v, u, w); 30 | } 31 | 32 | /**************************************************/ 33 | vector dep; 34 | vector dis; 35 | vector> par; 36 | int rt, LG; 37 | void dfs(int u, int fa, int d1, int d2) { 38 | dep[u] = d1; 39 | dis[u] = d2; 40 | if (u == rt) { 41 | for (int i = 0; i < LG; ++i) 42 | par[u][i] = rt; 43 | } else { 44 | par[u][0] = fa; 45 | for (int i = 1; i < LG; ++i) { 46 | par[u][i] = par[par[u][i - 1]][i - 1]; 47 | } 48 | } 49 | 50 | for (Edge& e : G[u]) { 51 | int v = e.v; 52 | T w = e.w; 53 | if (v == fa) 54 | continue; 55 | dfs(v, u, d1 + 1, d2 + w); 56 | } 57 | } 58 | 59 | inline void build_lca(int _rt) { 60 | rt = _rt; 61 | LG = __lg(V + 1) + 1; 62 | dep = vector(V + 1); 63 | dis = vector(V + 1); 64 | par = vector>(V + 1, vector(LG)); 65 | dfs(rt, rt, 0, 0); 66 | } 67 | 68 | inline int jump(int u, int d) { 69 | for (int j = LG - 1; j >= 0; --j) { 70 | if ((1 << j) & d) 71 | u = par[u][j]; 72 | } 73 | return u; 74 | } 75 | 76 | int lca(int u, int v) { 77 | if (dep[u] < dep[v]) 78 | swap(u, v); 79 | u = jump(u, dep[u] - dep[v]); 80 | if (u == v) 81 | return u; 82 | for (int i = LG - 1; i >= 0; --i) { 83 | if (par[u][i] != par[v][i]) { 84 | u = par[u][i]; 85 | v = par[v][i]; 86 | } 87 | } 88 | return par[u][0]; 89 | } 90 | }; 91 | 92 | }; // namespace Backlight -------------------------------------------------------------------------------- /src/graph/PointBCC.cpp: -------------------------------------------------------------------------------- 1 | std::vector> PointBCC(const std::vector>& g) { 2 | int n = g.size(); 3 | 4 | std::vector> bccs; 5 | std::vector belong(n, -1); 6 | std::vector is_cut(n, false); 7 | 8 | int dfs_clock = 0; 9 | std::vector dfn(n, -1), low(n); 10 | std::stack stack; 11 | std::function tarjan = [&](int u, int fa) { 12 | dfn[u] = low[u] = dfs_clock++; 13 | stack.push(u); 14 | 15 | int son = 0; 16 | for (int v : g[u]) { 17 | if (v == fa) 18 | continue; 19 | 20 | if (dfn[v] == -1) { 21 | tarjan(v, u); 22 | 23 | low[u] = std::min(low[u], low[v]); 24 | 25 | if (dfn[u] <= low[v]) { 26 | ++son; 27 | if (u != fa || son > 1) 28 | is_cut[u] = true; 29 | bccs.push_back({}); 30 | int top; 31 | do { 32 | top = stack.top(); 33 | stack.pop(); 34 | bccs.back().push_back(top); 35 | belong[top] = bccs.size() - 1; 36 | } while (top != v); 37 | bccs.back().push_back(u); 38 | belong[u] = bccs.size() - 1; 39 | } 40 | } else if (dfn[v] < dfn[u]) { 41 | low[u] = std::min(low[u], dfn[v]); 42 | } 43 | } 44 | 45 | if (u == fa && son == 0) { 46 | bccs.push_back({u}); 47 | belong[u] = bccs.size() - 1; 48 | } 49 | }; 50 | for (int i = 0; i < n; ++i) { 51 | if (dfn[i] == -1) { 52 | while (!stack.empty()) 53 | stack.pop(); 54 | tarjan(i, i); 55 | } 56 | } 57 | 58 | return bccs; 59 | } -------------------------------------------------------------------------------- /src/graph/SPFA.cpp: -------------------------------------------------------------------------------- 1 | namespace Backlight { 2 | 3 | template 4 | struct Wraph { 5 | struct Edge { 6 | int u, v; 7 | T w; 8 | Edge() {} 9 | Edge(int _u, int _v, T _w) 10 | : u(_u), v(_v), w(_w) {} 11 | }; 12 | 13 | int V; 14 | vector> G; 15 | 16 | Wraph() 17 | : V(0) {} 18 | Wraph(int _V) 19 | : V(_V), G(_V + 1) {} 20 | 21 | inline void addarc(int u, int v, T w) { 22 | assert(1 <= u && u <= V); 23 | assert(1 <= v && v <= V); 24 | G[u].push_back(Edge(u, v, w)); 25 | } 26 | 27 | inline void addedge(int u, int v, T w) { 28 | addarc(u, v, w); 29 | addarc(v, u, w); 30 | } 31 | 32 | /**************************************************/ 33 | vector spfa(int S, T T_MAX) { 34 | queue q; 35 | vector dis(V + 1, T_MAX); 36 | vector inq(V + 1, 0); 37 | q.push(S); 38 | dis[S] = 0; 39 | while (!q.empty()) { 40 | int u = q.front(); 41 | q.pop(); 42 | inq[u] = 0; 43 | for (Edge e : G[u]) { 44 | if (dis[e.v] > dis[u] + e.w) { 45 | dis[e.v] = dis[u] + e.w; 46 | if (!inq[e.v]) { 47 | inq[e.v] = 1; 48 | q.push(e.v); 49 | } 50 | } 51 | } 52 | } 53 | return dis; 54 | } 55 | }; 56 | 57 | } // namespace Backlight -------------------------------------------------------------------------------- /src/graph/TarjanSCC.cpp: -------------------------------------------------------------------------------- 1 | std::vector> TarjanSCC(const std::vector>& g) { 2 | int n = g.size(); 3 | 4 | int dfs_clock = 0; 5 | std::vector dfn(n, -1), low(n); 6 | std::vector in_stack(n, false); 7 | std::stack stk; 8 | 9 | int scc_count = 0; 10 | std::vector belong(n, -1); 11 | std::vector> sccs; 12 | 13 | std::function tarjan = [&](int u) { 14 | dfn[u] = low[u] = dfs_clock++; 15 | in_stack[u] = true; 16 | stk.push(u); 17 | 18 | for (int v : g[u]) { 19 | if (dfn[v] == -1) { 20 | tarjan(v); 21 | low[u] = std::min(low[u], low[v]); 22 | } else if (in_stack[v]) { 23 | low[u] = std::min(low[u], dfn[v]); 24 | } 25 | } 26 | 27 | if (dfn[u] == low[u]) { 28 | ++scc_count; 29 | sccs.push_back({}); 30 | 31 | int x; 32 | do { 33 | x = stk.top(); 34 | stk.pop(); 35 | 36 | in_stack[x] = false; 37 | belong[x] = scc_count - 1; 38 | sccs[scc_count - 1].push_back(x); 39 | } while (u != x); 40 | } 41 | }; 42 | for (int i = 0; i < n; ++i) { 43 | if (dfn[i] == -1) { 44 | tarjan(i); 45 | } 46 | } 47 | 48 | return sccs; 49 | } -------------------------------------------------------------------------------- /src/graph/TwoSAT.cpp: -------------------------------------------------------------------------------- 1 | class TwoSAT { 2 | private: 3 | public: 4 | TwoSAT(int n) : n_(n), g_(2 * n_), r_(2 * n_) {} 5 | 6 | int ID(int x, int y) { 7 | ASSERT(0 <= x && x < n_); 8 | ASSERT(y == 0 || y == 1); 9 | 10 | return 2 * x + y; 11 | } 12 | 13 | void Either(int x, int y) { 14 | g_[x ^ 1].push_back(y); 15 | r_[y].push_back(x ^ 1); 16 | 17 | g_[y ^ 1].push_back(x); 18 | r_[x].push_back(y ^ 1); 19 | } 20 | 21 | void Implies(int x, int y) { Either(x ^ 1, y); } 22 | 23 | void Must(int x) { Either(x, x); } 24 | 25 | std::pair> Solve() { 26 | int dfs_clock = 0; 27 | std::vector vis(2 * n_, false); 28 | std::vector dfn(2 * n_, -1); 29 | std::function dfs1 = [&](int u) { 30 | vis[u] = true; 31 | for (int v : g_[u]) { 32 | if (vis[v] == false) { 33 | dfs1(v); 34 | } 35 | } 36 | dfn[dfs_clock++] = u; 37 | }; 38 | for (int i = 0; i < 2 * n_; ++i) { 39 | if (!vis[i]) { 40 | dfs1(i); 41 | } 42 | } 43 | 44 | int c = 0; 45 | std::vector color(2 * n_, -1); 46 | std::function dfs2 = [&](int u) { 47 | color[u] = c; 48 | for (int v : r_[u]) { 49 | if (color[v] == -1) { 50 | dfs2(v); 51 | } 52 | } 53 | }; 54 | for (int i = 2 * n_ - 1; i >= 0; --i) { 55 | int u = dfn[i]; 56 | if (color[u] == -1) { 57 | dfs2(u); 58 | c++; 59 | } 60 | } 61 | 62 | for (int i = 0; i < n_; ++i) { 63 | if (color[2 * i] == color[2 * i + 1]) { 64 | return {false, {}}; 65 | } 66 | } 67 | 68 | std::vector values(n_, false); 69 | for (int i = 0; i < n_; ++i) { 70 | values[i] = color[2 * i] < color[2 * i + 1]; 71 | } 72 | 73 | return {true, values}; 74 | } 75 | 76 | private: 77 | int n_; 78 | std::vector> g_, r_; 79 | }; -------------------------------------------------------------------------------- /src/graph/Wraph.cpp: -------------------------------------------------------------------------------- 1 | namespace Backlight { 2 | 3 | template 4 | struct Wraph { 5 | struct Edge { 6 | int u, v; 7 | T w; 8 | Edge() {} 9 | Edge(int _u, int _v, T _w) 10 | : u(_u), v(_v), w(_w) {} 11 | }; 12 | 13 | int V; 14 | vector> G; 15 | 16 | Wraph() 17 | : V(0) {} 18 | Wraph(int _V) 19 | : V(_V), G(_V + 1) {} 20 | 21 | inline void addarc(int u, int v, T w = 1) { 22 | assert(1 <= u && u <= V); 23 | assert(1 <= v && v <= V); 24 | G[u].push_back(Edge(u, v, w)); 25 | } 26 | 27 | inline void addedge(int u, int v, T w = 1) { 28 | addarc(u, v, w); 29 | addarc(v, u, w); 30 | } 31 | }; 32 | 33 | } // namespace Backlight -------------------------------------------------------------------------------- /src/graph/dsu-on-tree.cpp: -------------------------------------------------------------------------------- 1 | // CF600E 2 | // 对于每个节点,输出其子树中出现次数最多的颜色之和。 3 | vector G[N]; 4 | inline void addedge(int u, int v) { 5 | G[u].push_back(v); 6 | G[v].push_back(u); 7 | } 8 | 9 | int n, color[N]; 10 | 11 | int sz[N], son[N], cnt[N], ma; 12 | ll cur, ans[N]; 13 | void dfs1(int u, int fa) { 14 | sz[u] = 1; 15 | son[u] = -1; 16 | for (int v : G[u]) { 17 | if (v == fa) 18 | continue; 19 | dfs1(v, u); 20 | sz[u] += sz[v]; 21 | if (sz[v] > sz[son[u]]) 22 | son[u] = v; 23 | } 24 | } 25 | 26 | void add(int u, int fa, int Son, int d) { 27 | // update data here 28 | cnt[color[u]] += d; 29 | if (cnt[color[u]] > ma) 30 | ma = cnt[color[u]], cur = 0; 31 | if (cnt[color[u]] == ma) 32 | cur += color[u]; 33 | 34 | for (int v : G[u]) { 35 | if (v == fa || v == Son) 36 | continue; 37 | add(v, u, Son, d); 38 | } 39 | } 40 | 41 | void dfs2(int u, int fa, bool keep) { 42 | for (int v : G[u]) { 43 | if (v == fa || v == son[u]) 44 | continue; 45 | dfs2(v, u, false); 46 | } 47 | if (son[u] != -1) 48 | dfs2(son[u], u, true); 49 | 50 | add(u, fa, son[u], 1); 51 | 52 | // answer queries here 53 | ans[u] = cur; 54 | 55 | if (!keep) { 56 | add(u, fa, -1, -1); 57 | ma = 0; 58 | cur = 0; 59 | } 60 | } 61 | 62 | void solve() { 63 | read(n); 64 | FOR(i, 1, n) 65 | read(color[i]); 66 | 67 | int u, v; 68 | FOR(i, 2, n) { 69 | read(u, v); 70 | addedge(u, v); 71 | } 72 | 73 | dfs1(1, 0); 74 | dfs2(1, 0, 0); 75 | 76 | FOR(i, 1, n - 1) 77 | printf("%lld ", ans[i]); 78 | println(ans[n]); 79 | } -------------------------------------------------------------------------------- /src/graph/maxflow.cpp: -------------------------------------------------------------------------------- 1 | // Problem: P3376 【模板】网络最大流 2 | // Contest: Luogu 3 | // URL: https://www.luogu.com.cn/problem/P3376 4 | // Memory Limit: 128 MB 5 | // Time Limit: 2000 ms 6 | // 7 | // Powered by CP Editor (https://cpeditor.org) 8 | 9 | #include 10 | 11 | #define CPPIO \ 12 | std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0); 13 | #define freep(p) p ? delete p, p = nullptr, void(1) : void(0) 14 | 15 | #ifdef BACKLIGHT 16 | #include "debug.h" 17 | #else 18 | #define logd(...) ; 19 | #endif 20 | 21 | using i64 = int64_t; 22 | using u64 = uint64_t; 23 | 24 | void solve_case(int Case); 25 | 26 | int main(int argc, char* argv[]) { 27 | CPPIO; 28 | int T = 1; 29 | // std::cin >> T; 30 | for (int t = 1; t <= T; ++t) { 31 | solve_case(t); 32 | } 33 | return 0; 34 | } 35 | 36 | template 37 | class MaxFlowGraph { 38 | struct Edge { 39 | int from, to; 40 | CapacityType capacity, flow; 41 | Edge() {} 42 | Edge(int _from, int _to, CapacityType _capacity, CapacityType _flow) 43 | : from(_from), to(_to), capacity(_capacity), flow(_flow) {} 44 | }; 45 | 46 | int n_; 47 | int m_; 48 | std::vector edges_; 49 | std::vector> adjacent_; 50 | 51 | public: 52 | explicit MaxFlowGraph(int n) : n_(n), m_(0), edges_(0), adjacent_(n) {} 53 | 54 | void AddEdge(int from, int to, CapacityType capacity) { 55 | assert(0 <= from and from < n_); 56 | assert(0 <= to and to < n_); 57 | 58 | edges_.emplace_back(from, to, capacity, 0); 59 | adjacent_[from].push_back(m_); 60 | ++m_; 61 | 62 | edges_.emplace_back(to, from, 0, 0); 63 | adjacent_[to].push_back(m_); 64 | ++m_; 65 | } 66 | 67 | CapacityType Dinic(int src, int dst) { 68 | const static CapacityType INF = std::numeric_limits::max(); 69 | std::vector level(n_); 70 | std::vector start_index(n_); 71 | 72 | std::function bfs = [&]() -> bool { 73 | std::fill(level.begin(), level.end(), -1); 74 | 75 | std::queue q; 76 | q.push(src); 77 | level[src] = 0; 78 | 79 | while (!q.empty()) { 80 | int u = q.front(); 81 | q.pop(); 82 | 83 | for (int edge_id : adjacent_[u]) { 84 | auto [from, to, capacity, flow] = edges_[edge_id]; 85 | CapacityType residual_capacity = capacity - flow; 86 | if (residual_capacity > 0 && level[to] == -1) { 87 | level[to] = level[u] + 1; 88 | if (to == dst) 89 | break; 90 | q.push(to); 91 | } 92 | } 93 | } 94 | 95 | return level[dst] != -1; 96 | }; 97 | 98 | std::function dfs = 99 | [&](int u, CapacityType max_augment) -> CapacityType { 100 | if (u == dst) 101 | return max_augment; 102 | 103 | if (max_augment == 0) 104 | return 0; 105 | 106 | CapacityType total_augment = 0; 107 | int i = start_index[u]; 108 | for (; i < (int)adjacent_[u].size(); ++i) { 109 | int edge_id = adjacent_[u][i]; 110 | auto [from, to, capacity, flow] = edges_[edge_id]; 111 | if (level[to] == level[u] + 1) { 112 | CapacityType residual_capacity = capacity - flow; 113 | CapacityType new_augment = 114 | dfs(to, std::min(max_augment, residual_capacity)); 115 | if (new_augment <= 0) 116 | continue; 117 | 118 | max_augment -= new_augment; 119 | total_augment += new_augment; 120 | edges_[edge_id].flow += new_augment; 121 | edges_[edge_id ^ 1].flow -= new_augment; 122 | 123 | if (max_augment == 0) 124 | break; 125 | } 126 | } 127 | start_index[u] = i; 128 | 129 | if (total_augment == 0) 130 | level[u] = -1; 131 | 132 | return total_augment; 133 | }; 134 | 135 | CapacityType max_flow = 0; 136 | while (bfs()) { 137 | std::fill(start_index.begin(), start_index.end(), 0); 138 | CapacityType new_flow = dfs(src, INF); 139 | logd(new_flow); 140 | max_flow += new_flow; 141 | } 142 | 143 | return max_flow; 144 | } 145 | 146 | std::vector Cut(int s) { 147 | std::vector visited(n_, false); 148 | 149 | std::function dfs = [&](int u) { 150 | visited[u] = true; 151 | for (int edge_id : adjacent_[u]) { 152 | auto [from, to, capacity, flow] = edges_[edge_id]; 153 | if (visited[to] || capacity == flow) 154 | continue; 155 | 156 | dfs(to); 157 | } 158 | }; 159 | dfs(s); 160 | 161 | return visited; 162 | } 163 | }; 164 | 165 | void solve_case(int Case) { 166 | int n, m, s, t; 167 | std::cin >> n >> m >> s >> t; 168 | --s, --t; 169 | MaxFlowGraph g(n); 170 | for (int i = 0, u, v, w; i < m; ++i) { 171 | std::cin >> u >> v >> w; 172 | --u, --v; 173 | g.AddEdge(u, v, w); 174 | } 175 | std::cout << g.Dinic(s, t) << "\n"; 176 | } 177 | -------------------------------------------------------------------------------- /src/graph/mincostflow.cpp: -------------------------------------------------------------------------------- 1 | // Problem: P3381 【模板】最小费用最大流 2 | // Contest: Luogu 3 | // URL: https://www.luogu.com.cn/problem/P3381 4 | // Memory Limit: 128 MB 5 | // Time Limit: 1000 ms 6 | // 7 | // Powered by CP Editor (https://cpeditor.org) 8 | 9 | #include 10 | 11 | #define CPPIO \ 12 | std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0); 13 | #define freep(p) p ? delete p, p = nullptr, void(1) : void(0) 14 | 15 | #ifdef BACKLIGHT 16 | #include "debug.h" 17 | #else 18 | #define logd(...) ; 19 | #endif 20 | 21 | using i64 = int64_t; 22 | using u64 = uint64_t; 23 | 24 | void solve_case(int Case); 25 | 26 | int main(int argc, char* argv[]) { 27 | CPPIO; 28 | int T = 1; 29 | // std::cin >> T; 30 | for (int t = 1; t <= T; ++t) { 31 | solve_case(t); 32 | } 33 | return 0; 34 | } 35 | 36 | template 37 | class MinCostMaxFlowGraph { 38 | private: 39 | struct Edge { 40 | int from, to; 41 | CapacityType capacity; 42 | CostType cost; 43 | Edge() {} 44 | Edge(int _from, int _to, CapacityType _capacity, CostType _cost) 45 | : from(_from), to(_to), capacity(_capacity), cost(_cost) {} 46 | }; 47 | int n_; 48 | int m_; 49 | std::vector edges_; 50 | std::vector> adjacent_; 51 | 52 | public: 53 | MinCostMaxFlowGraph(int n) : n_(n), m_(0), edges_(0), adjacent_(n) {} 54 | 55 | void AddEdge(int u, int v, CapacityType capacity, CostType cost) { 56 | assert(0 <= u and u < n_); 57 | assert(0 <= v and v < n_); 58 | 59 | edges_.push_back(Edge(u, v, capacity, cost)); 60 | adjacent_[u].push_back(m_); 61 | ++m_; 62 | 63 | edges_.push_back(Edge(v, u, 0, -cost)); 64 | adjacent_[v].push_back(m_); 65 | ++m_; 66 | } 67 | 68 | std::pair PrimalDual(int src, int dst) { 69 | const static CapacityType INF = std::numeric_limits::max(); 70 | 71 | std::vector h(n_); 72 | std::vector inq(n_); 73 | std::function spfa = [&]() -> void { 74 | std::fill(h.begin(), h.end(), INF); 75 | 76 | std::queue q; 77 | q.push(src); 78 | inq[src] = true; 79 | h[src] = 0; 80 | while (!q.empty()) { 81 | int u = q.front(); 82 | q.pop(); 83 | inq[u] = false; 84 | 85 | for (int edge_id : adjacent_[u]) { 86 | auto [from, to, capacity, cost] = edges_[edge_id]; 87 | if (capacity <= 0 || h[to] <= h[from] + cost) 88 | continue; 89 | h[to] = h[from] + cost; 90 | if (!inq[to]) { 91 | q.push(to); 92 | inq[to] = true; 93 | } 94 | } 95 | } 96 | }; 97 | 98 | std::vector d(n_); 99 | std::vector vis(n_); 100 | std::vector prev(n_); 101 | std::function dijkstra = [&]() -> bool { 102 | std::fill(d.begin(), d.end(), INF); 103 | std::fill(vis.begin(), vis.end(), false); 104 | 105 | std::priority_queue> q; 106 | d[src] = 0; 107 | q.push(std::make_pair(-d[src], src)); 108 | 109 | while (!q.empty()) { 110 | auto [_, u] = q.top(); 111 | q.pop(); 112 | 113 | if (vis[u]) 114 | continue; 115 | vis[u] = true; 116 | 117 | for (int edge_id : adjacent_[u]) { 118 | auto [from, to, capacity, cost] = edges_[edge_id]; 119 | CostType new_cost = cost + h[from] - h[to]; 120 | 121 | if (vis[to] || capacity <= 0 || d[to] <= d[from] + new_cost) 122 | continue; 123 | 124 | d[to] = d[from] + new_cost; 125 | prev[to] = edge_id; 126 | q.push(std::make_pair(-d[to], to)); 127 | } 128 | } 129 | 130 | return d[dst] != INF; 131 | }; 132 | 133 | spfa(); 134 | 135 | CapacityType max_flow = 0; 136 | CostType min_cost = 0; 137 | while (dijkstra()) { 138 | CapacityType augment = INF; 139 | for (int p = dst; p != src; p = edges_[prev[p] ^ 1].to) { 140 | augment = std::min(augment, edges_[prev[p]].capacity); 141 | } 142 | 143 | max_flow += augment; 144 | for (int p = dst; p != src; p = edges_[prev[p] ^ 1].to) { 145 | min_cost += edges_[prev[p]].cost * augment; 146 | edges_[prev[p]].capacity -= augment; 147 | edges_[prev[p] ^ 1].capacity += augment; 148 | } 149 | 150 | for (int i = 0; i < n_; ++i) 151 | h[i] += d[i]; 152 | } 153 | 154 | return {min_cost, max_flow}; 155 | } 156 | }; 157 | 158 | void solve_case(int Case) { 159 | int n, m, s, t; 160 | std::cin >> n >> m >> s >> t; 161 | --s, --t; 162 | 163 | MinCostMaxFlowGraph g(n); 164 | for (int i = 0, u, v, cap, cost; i < m; ++i) { 165 | std::cin >> u >> v >> cap >> cost; 166 | --u, --v; 167 | g.addedge(u, v, cap, cost); 168 | } 169 | 170 | auto [min_cost, max_flow] = g.PrimalDual(s, t); 171 | 172 | std::cout << max_flow << " " << min_cost << "\n"; 173 | } -------------------------------------------------------------------------------- /src/graph/tree-divide.cpp: -------------------------------------------------------------------------------- 1 | struct Edge { 2 | int v, w; 3 | Edge() {} 4 | Edge(int _v, int _w) 5 | : v(_v), w(_w) {} 6 | }; 7 | 8 | vector G[N]; 9 | inline void addedge(int u, int v, int w) { 10 | G[u].push_back(Edge(v, w)); 11 | G[v].push_back(Edge(u, w)); 12 | } 13 | 14 | bool vis[N]; 15 | int sz[N], max_sz[N]; 16 | void dfs_size(int u, int fa) { 17 | sz[u] = 1; 18 | max_sz[u] = 0; 19 | for (const Edge& e : G[u]) { 20 | int v = e.v; 21 | if (v == fa || vis[v]) 22 | continue; 23 | dfs_size(v, u); 24 | sz[u] += sz[v]; 25 | max_sz[u] = max(max_sz[u], sz[v]); 26 | } 27 | } 28 | 29 | int Max, rt; 30 | void dfs_root(int r, int u, int fa) { 31 | max_sz[u] = max(max_sz[u], sz[r] - sz[u]); 32 | if (Max > max_sz[u]) 33 | Max = max_sz[u], rt = u; 34 | for (const Edge& e : G[u]) { 35 | int v = e.v; 36 | if (v == fa || vis[v]) 37 | continue; 38 | dfs_root(r, v, u); 39 | } 40 | } 41 | 42 | int dcnt, dis[N]; 43 | void dfs_dis(int u, int fa, int d) { 44 | dis[++dcnt] = d; 45 | for (const Edge& e : G[u]) { 46 | int v = e.v, w = e.w; 47 | if (v == fa || vis[v]) 48 | continue; 49 | dfs_dis(v, u, d + w); 50 | } 51 | } 52 | 53 | int ans[K]; 54 | void calc(int u, int w, int delta) { 55 | dcnt = 0; 56 | dfs_dis(u, -1, w); 57 | for (int i = 1; i <= dcnt; ++i) { 58 | for (int j = i + 1; j <= dcnt; ++j) { 59 | ans[dis[i] + dis[j]] += delta; 60 | } 61 | } 62 | } 63 | 64 | int n, m; 65 | void DFS(int u) { 66 | Max = n; 67 | dfs_size(u, -1); 68 | dfs_root(u, u, -1); 69 | vis[rt] = 1; 70 | calc(rt, 0, 1); 71 | for (const Edge& e : G[rt]) { 72 | int v = e.v, w = e.w; 73 | if (vis[v]) 74 | continue; 75 | calc(v, w, -1); 76 | DFS(v); 77 | } 78 | } 79 | 80 | void solve() { 81 | read(n, m); 82 | 83 | int u, v, w; 84 | FOR(i, 2, n) { 85 | read(u, v, w); 86 | addedge(u, v, w); 87 | } 88 | 89 | DFS(1); 90 | 91 | int k; 92 | FOR(i, 1, m) { 93 | read(k); 94 | puts(ans[k] ? "AYE" : "NAY"); 95 | } 96 | } -------------------------------------------------------------------------------- /src/math/BSGS.cpp: -------------------------------------------------------------------------------- 1 | namespace Backlight { 2 | 3 | namespace BSGS { 4 | typedef long long ll; 5 | 6 | ll exgcd(ll a, ll b, ll& x, ll& y) { 7 | if (b == 0) { 8 | x = 1; 9 | y = 0; 10 | return a; 11 | } 12 | ll d = exgcd(b, a % b, x, y); 13 | ll z = x; 14 | x = y; 15 | y = z - y * (a / b); 16 | return d; 17 | } 18 | 19 | ll qpow(ll a, ll n, ll p) { 20 | ll ans = 1; 21 | for (; n; n >>= 1) { 22 | if (n & 1) 23 | ans = ans * a % p; 24 | a = a * a % p; 25 | } 26 | return ans; 27 | } 28 | 29 | // solve a^x = b (mod p), p is a prime must hold 30 | ll BSGS(ll a, ll b, ll p) { 31 | unordered_map mp; 32 | if (__gcd(a, p) != 1) 33 | return -1; 34 | if (b % p == 1) 35 | return 0; 36 | a %= p; 37 | b %= p; 38 | ll k = sqrt(p), t = qpow(a, k, p), s = b; 39 | for (int i = 0; i <= k; i++, s = s * a % p) 40 | mp[s] = i; 41 | s = 1; 42 | for (int i = 0; i <= k; i++, s = s * t % p) { 43 | int ans = mp.count(s) ? mp[s] : -1; 44 | if (ans != -1 && i * k - ans >= 0) 45 | return i * k - ans; 46 | } 47 | return -1; 48 | } 49 | 50 | // solve a^x = b (mod p), p don't need to be a prime 51 | ll EXBSGS(ll a, ll b, ll p) { 52 | ll k = 0, d, c = 1, x, y; 53 | a %= p; 54 | b %= p; 55 | if (a == b) 56 | return 1; 57 | if (b == 1) 58 | return 0; 59 | while ((d = __gcd(a, p)) != 1) { 60 | if (b % d) 61 | return -1; 62 | k++; 63 | b /= d; 64 | p /= d; 65 | c = c * (a / d) % p; 66 | if (c == b) 67 | return k; 68 | } 69 | if (p == 1) 70 | return k; 71 | exgcd(c, p, x, y); 72 | b = (b * x % p + p) % p; 73 | a %= p; 74 | ll ans = BSGS(a, b, p); 75 | return ans == -1 ? ans : ans + k; 76 | } 77 | } // namespace BSGS 78 | 79 | } // namespace Backlight -------------------------------------------------------------------------------- /src/math/CRT.cpp: -------------------------------------------------------------------------------- 1 | namespace Backlight { 2 | 3 | // get x, y for ax + by = GCD(a, b) 4 | ll exgcd(ll a, ll b, ll& x, ll& y) { 5 | if (b == 0) { 6 | x = 1; 7 | y = 0; 8 | return a; 9 | } 10 | ll d = exgcd(b, a % b, x, y); 11 | ll z = x; 12 | x = y; 13 | y = z - y * (a / b); 14 | return d; 15 | } 16 | 17 | // CRT: solve x = a_i (mod m_i) for i in [0, n) 18 | 19 | // GCD(m_i, m_j) = 1 hold 20 | ll CRT(vector& a, vector& m) { 21 | assert(a.size() == m.size()); 22 | assert(a.size() > 0); 23 | int n = a.size(); 24 | ll M = 1, res = 0; 25 | for (int i = 0; i < n; ++i) 26 | M *= m[i]; 27 | ll _M, x, y; 28 | for (int i = 0; i < n; ++i) { 29 | _M = M / m[i]; 30 | exgcd(_M, m[i], x, y); 31 | res = (res + a[i] * _M % M * x % M) % M; 32 | } 33 | if (res < 0) 34 | res += M; 35 | return res; 36 | } 37 | 38 | ll mul(ll a, ll b, ll mod) { 39 | ll res = 0; 40 | while (b) { 41 | if (b & 1) 42 | res = (res + a) % mod; 43 | b >>= 1; 44 | a = (a + a) % mod; 45 | } 46 | return res; 47 | } 48 | 49 | // GCD(m_i, m_j) = 1 not hold 50 | ll EXCRT(vector& a, vector& m) { 51 | assert(a.size() == m.size()); 52 | assert(a.size() > 0); 53 | int n = a.size(); 54 | ll res = a[0], M = m[0], B, g, x, y; 55 | for (int i = 1; i < n; ++i) { 56 | B = ((a[i] - res) % m[i] + m[i]) % m[i]; 57 | g = exgcd(M, m[i], x, y); 58 | x = mul(x, B / g, m[i]); 59 | res += M * x; 60 | M *= m[i] / g; 61 | res = (res + M) % M; 62 | } 63 | return res; 64 | } 65 | 66 | } // namespace Backlight -------------------------------------------------------------------------------- /src/math/Cipolla.cpp: -------------------------------------------------------------------------------- 1 | namespace Backlight { 2 | 3 | namespace Cipolla { 4 | mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count()); 5 | ll W, P; 6 | struct complex { 7 | ll r, i; 8 | complex(ll _r, ll _i) 9 | : r(_r), i(_i) {} 10 | inline complex operator*(const complex& c) const { return complex((r * c.r % P + i * c.i % P * W) % P, (r * c.i % P + i * c.r % P) % P); } 11 | }; 12 | 13 | inline complex pow(complex a, int b) { 14 | complex res(1, 0); 15 | while (b) { 16 | if (b & 1) 17 | res = res * a; 18 | a = a * a; 19 | b >>= 1; 20 | } 21 | return res; 22 | } 23 | 24 | inline ll pow(ll a, ll b, ll p) { 25 | ll res = 1; 26 | while (b) { 27 | if (b & 1) 28 | res = res * a % p; 29 | a = a * a % p; 30 | b >>= 1; 31 | } 32 | return res; 33 | } 34 | 35 | // solve x for x^2 = a (mod p) 36 | ll solve(ll a, ll p) { 37 | P = p; 38 | a %= p; 39 | if (a == 0) 40 | return 0; 41 | 42 | ll t = pow(a, (p - 1) / 2, p); 43 | if (t != 1) 44 | return -1; 45 | while (true) { 46 | t = rnd() % p; 47 | ll c = (t * t % p + p - a) % p; 48 | if (pow(c, (p - 1) / 2, p) == p - 1) 49 | break; 50 | } 51 | 52 | W = (t * t % p + p - a) % p; 53 | ll x = pow(complex(t, 1), (p + 1) / 2).r; 54 | return x; 55 | } 56 | 57 | } // namespace Cipolla 58 | 59 | } // namespace Backlight -------------------------------------------------------------------------------- /src/math/EXGCD.cpp: -------------------------------------------------------------------------------- 1 | namespace Backlight { 2 | 3 | // get x_0, y_0 for ax + by = GCD(a, b) 4 | // x = x_0 + bt 5 | // y = y_0 - at 6 | // for all interger t 7 | #define EXGCD 8 | ll exgcd(ll a, ll b, ll& x, ll& y) { 9 | if (b == 0) { 10 | x = 1; 11 | y = 0; 12 | return a; 13 | } 14 | ll d = exgcd(b, a % b, x, y); 15 | ll z = x; 16 | x = y; 17 | y = z - y * (a / b); 18 | return d; 19 | } 20 | 21 | } // namespace Backlight -------------------------------------------------------------------------------- /src/math/EulerSeive.cpp: -------------------------------------------------------------------------------- 1 | namespace Backlight { 2 | 3 | vector euler_seive(int n) { 4 | vector primes; 5 | vector is(n + 1, 1); 6 | 7 | for (int i = 2; i <= n; ++i) { 8 | if (is[i]) 9 | primes.push_back(i); 10 | for (int j = 0; j < (int)primes.size(); ++j) { 11 | ll nxt = 1ll * primes[j] * i; 12 | if (nxt > n) 13 | break; 14 | is[nxt] = false; 15 | if (i % primes[j] == 0) 16 | break; 17 | } 18 | } 19 | return primes; 20 | } 21 | 22 | } // namespace Backlight -------------------------------------------------------------------------------- /src/math/FFT.cpp: -------------------------------------------------------------------------------- 1 | namespace FFT { 2 | const long double PI = acos(-1.0); 3 | using LL = int64_t; 4 | struct Complex { 5 | long double r, i; 6 | Complex() 7 | : r(0), i(0) {} 8 | Complex(long double _r, long double _i) 9 | : r(_r), i(_i) {} 10 | Complex conjugation() { return Complex(r, -i); } 11 | inline Complex operator-(const Complex& c) const { 12 | return Complex(r - c.r, i - c.i); 13 | } 14 | inline Complex operator+(const Complex& c) const { 15 | return Complex(r + c.r, i + c.i); 16 | } 17 | inline Complex operator*(const Complex& c) const { 18 | return Complex(r * c.r - i * c.i, r * c.i + i * c.r); 19 | } 20 | inline Complex operator/(const int d) const { return Complex(r / d, i / d); } 21 | }; 22 | ostream& operator<<(ostream& os, const Complex& c) { 23 | return os << "(" << c.r << ", " << c.i << ")"; 24 | } 25 | 26 | int N; 27 | vector r; 28 | void prework(int n) { 29 | N = 1; 30 | while (N <= n) 31 | N <<= 1; 32 | r.resize(N); 33 | // r[0] = 0; 34 | for (int i = 1; i < N; ++i) 35 | r[i] = (r[i >> 1] >> 1) | ((i & 1) ? (N >> 1) : 0); 36 | } 37 | 38 | inline void FFT(vector& a) { 39 | for (int i = 1; i < N; ++i) 40 | if (i < r[i]) 41 | swap(a[i], a[r[i]]); 42 | for (int i = 2; i <= N; i <<= 1) { 43 | int l = i >> 1; 44 | Complex w, x, wn(cos(PI / l), sin(PI / l)); 45 | for (int j = 0; j < N; j += i) { 46 | w = Complex(1, 0); 47 | for (int k = j; k < j + l; ++k) { 48 | x = a[k + l] * w; 49 | a[k + l] = a[k] - x; 50 | a[k] = a[k] + x; 51 | w = w * wn; 52 | } 53 | } 54 | } 55 | } 56 | inline void IFT(vector& a) { 57 | FFT(a); 58 | reverse(a.begin() + 1, a.end()); 59 | for (int i = 0; i < N; i++) 60 | a[i] = a[i] / N; 61 | } 62 | 63 | vector convolution(const vector& f, const vector& g) { 64 | int n = f.size(), m = g.size(), k = n + m - 1; 65 | prework(k); 66 | vector a(N), b(N); 67 | for (int i = 0; i < n; ++i) 68 | a[i] = Complex(f[i], 0); 69 | for (int i = 0; i < m; ++i) 70 | b[i] = Complex(g[i], 0); 71 | 72 | FFT(a); 73 | FFT(b); 74 | for (int i = 0; i < N; ++i) 75 | a[i] = a[i] * b[i]; 76 | IFT(a); 77 | 78 | vector h(k); 79 | for (int i = 0; i < k; ++i) 80 | h[i] = int(a[i].r + 0.5); 81 | return h; 82 | } 83 | 84 | // 任意模数FFT 85 | vector convolution(const vector& f, const vector& g, int p) { 86 | int n = f.size(), m = g.size(), k = n + m - 1; 87 | prework(k); 88 | vector a(N), b(N), c(N), d(N); 89 | for (int i = 0; i < n; ++i) 90 | a[i] = Complex(f[i] >> 15, f[i] & 32767); 91 | for (int i = 0; i < m; ++i) 92 | c[i] = Complex(g[i] >> 15, g[i] & 32767); 93 | 94 | FFT(a); 95 | b[0] = a[0].conjugation(); 96 | for (int i = 1; i < N; ++i) 97 | b[i] = a[N - i].conjugation(); 98 | FFT(c); 99 | d[0] = c[0].conjugation(); 100 | for (int i = 1; i < N; ++i) 101 | d[i] = c[N - i].conjugation(); 102 | 103 | for (int i = 0; i < N; ++i) { 104 | Complex aa, bb, cc, dd; 105 | aa = (a[i] + b[i]) * Complex(0.5, 0); 106 | bb = (a[i] - b[i]) * Complex(0, -0.5); 107 | cc = (c[i] + d[i]) * Complex(0.5, 0); 108 | dd = (c[i] - d[i]) * Complex(0, -0.5); 109 | a[i] = aa * cc + Complex(0, 1) * (aa * dd + bb * cc); 110 | b[i] = bb * dd; 111 | } 112 | 113 | IFT(a); 114 | IFT(b); 115 | 116 | vector h(k); 117 | for (int i = 0; i < k; ++i) { 118 | int aa, bb, cc; 119 | aa = LL(a[i].r + 0.5) % p; 120 | bb = LL(a[i].i + 0.5) % p; 121 | cc = LL(b[i].r + 0.5) % p; 122 | h[i] = 123 | ((1ll * aa * (1 << 30) % p + 1ll * bb * (1 << 15) % p + cc) % p + p) % 124 | p; 125 | } 126 | return h; 127 | } 128 | 129 | } // namespace FFT -------------------------------------------------------------------------------- /src/math/FWT.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | const int MOD = 998244353; 5 | 6 | inline int add(int x, int y) { 7 | return x + y >= MOD ? x + y - MOD : x + y; 8 | } 9 | inline int mul(int x, int y) { 10 | return 1ll * x * y % MOD; 11 | } 12 | inline int sub(int x, int y) { 13 | return x - y < 0 ? x - y + MOD : x - y; 14 | } 15 | inline int qp(int x, int y) { 16 | int r = 1; 17 | for (; y; y >>= 1) { 18 | if (y & 1) 19 | r = mul(r, x); 20 | x = mul(x, x); 21 | } 22 | return r; 23 | } 24 | inline int inv(int x) { 25 | return qp(x, MOD - 2); 26 | } 27 | inline int dvd(int x, int y) { 28 | return 1ll * x * qp(y, MOD - 2) % MOD; 29 | } 30 | 31 | namespace FWT { 32 | void OR(int* a, int n) { 33 | for (int o = 2, k = 1; o <= n; o <<= 1, k <<= 1) 34 | for (int i = 0; i < n; i += o) 35 | for (int j = 0; j < k; ++j) 36 | a[i + j + k] = add(a[i + j + k], a[i + j]); 37 | } 38 | 39 | void IOR(int* a, int n) { 40 | for (int o = 2, k = 1; o <= n; o <<= 1, k <<= 1) 41 | for (int i = 0; i < n; i += o) 42 | for (int j = 0; j < k; ++j) 43 | a[i + j + k] = sub(a[i + j + k], a[i + j]); 44 | } 45 | 46 | void AND(int* a, int n) { 47 | for (int o = 2, k = 1; o <= n; o <<= 1, k <<= 1) 48 | for (int i = 0; i < n; i += o) 49 | for (int j = 0; j < k; ++j) 50 | a[i + j] = add(a[i + j], a[i + j + k]); 51 | } 52 | 53 | void IAND(int* a, int n) { 54 | for (int o = 2, k = 1; o <= n; o <<= 1, k <<= 1) 55 | for (int i = 0; i < n; i += o) 56 | for (int j = 0; j < k; ++j) 57 | a[i + j] = sub(a[i + j], a[i + j + k]); 58 | } 59 | 60 | void XOR(int* a, int n) { 61 | int x, y; 62 | for (int o = 2, k = 1; o <= n; o <<= 1, k <<= 1) 63 | for (int i = 0; i < n; i += o) 64 | for (int j = 0; j < k; ++j) { 65 | x = a[i + j], y = a[i + j + k]; 66 | a[i + j] = add(x, y); 67 | a[i + j + k] = sub(x, y); 68 | } 69 | } 70 | 71 | int inv2 = inv(2); 72 | void IXOR(int* a, int n) { 73 | int x, y; 74 | for (int o = 2, k = 1; o <= n; o <<= 1, k <<= 1) 75 | for (int i = 0; i < n; i += o) 76 | for (int j = 0; j < k; ++j) { 77 | x = a[i + j], y = a[i + j + k]; 78 | a[i + j] = mul(add(x, y), inv2); 79 | a[i + j + k] = mul(sub(x, y), inv2); 80 | } 81 | } 82 | } // namespace FWT 83 | 84 | const int N = (1 << 17) + 5; 85 | 86 | int n; 87 | int A[N], B[N], a[N], b[N], c[N]; 88 | 89 | int main() { 90 | scanf("%d", &n); 91 | n = 1 << n; 92 | 93 | int x; 94 | for (int i = 0; i < n; ++i) 95 | scanf("%d", &A[i]); 96 | for (int i = 0; i < n; ++i) 97 | scanf("%d", &B[i]); 98 | 99 | // OR 100 | for (int i = 0; i < n; ++i) 101 | a[i] = A[i], b[i] = B[i]; 102 | FWT::OR(a, n); 103 | FWT::OR(b, n); 104 | for (int i = 0; i < n; ++i) 105 | c[i] = mul(a[i], b[i]); 106 | FWT::IOR(c, n); 107 | 108 | for (int i = 0; i < n - 1; ++i) 109 | printf("%d ", c[i]); 110 | printf("%d\n", c[n - 1]); 111 | 112 | // AND 113 | for (int i = 0; i < n; ++i) 114 | a[i] = A[i], b[i] = B[i]; 115 | FWT::AND(a, n); 116 | FWT::AND(b, n); 117 | for (int i = 0; i < n; ++i) 118 | c[i] = mul(a[i], b[i]); 119 | FWT::IAND(c, n); 120 | for (int i = 0; i < n - 1; ++i) 121 | printf("%d ", c[i]); 122 | printf("%d\n", c[n - 1]); 123 | 124 | // XOR 125 | for (int i = 0; i < n; ++i) 126 | a[i] = A[i], b[i] = B[i]; 127 | FWT::XOR(a, n); 128 | FWT::XOR(b, n); 129 | for (int i = 0; i < n; ++i) 130 | c[i] = mul(a[i], b[i]); 131 | FWT::IXOR(c, n); 132 | for (int i = 0; i < n - 1; ++i) 133 | printf("%d ", c[i]); 134 | printf("%d\n", c[n - 1]); 135 | return 0; 136 | } -------------------------------------------------------------------------------- /src/math/LinearBasis.cpp: -------------------------------------------------------------------------------- 1 | struct LinearBasis { 2 | static const int B = 62; 3 | ll b[B]; 4 | int tot, n; 5 | 6 | LinearBasis() { 7 | tot = 0; 8 | n = 0; 9 | memset(b, 0, sizeof(b)); 10 | } 11 | 12 | bool insert(ll x) { 13 | ++n; 14 | for (int i = B - 1; i >= 0; --i) { 15 | if (!(x >> i)) 16 | continue; 17 | if (!b[i]) { 18 | ++tot; 19 | b[i] = x; 20 | break; 21 | } 22 | x ^= b[i]; 23 | } 24 | return x > 0; 25 | } 26 | 27 | bool query(ll x) { 28 | for (int i = B - 1; i >= 0; --i) { 29 | if (!(x >> i)) 30 | continue; 31 | if (!b[i]) 32 | return false; 33 | x ^= b[i]; 34 | } 35 | return x == 0; 36 | } 37 | 38 | ll queryMax() { 39 | ll res = 0; 40 | for (int i = B - 1; i >= 0; --i) { 41 | if ((res ^ b[i]) > res) 42 | res ^= b[i]; 43 | } 44 | return res; 45 | } 46 | 47 | ll queryMin() { 48 | for (int i = 0; i < B; ++i) 49 | if (b[i]) 50 | return b[i]; 51 | return -1; 52 | } 53 | 54 | ll count() { 55 | return 1LL << tot; 56 | } 57 | 58 | void rebuild() { 59 | for (int i = B - 1; i >= 0; --i) { 60 | for (int j = i - 1; j >= 0; --j) { 61 | if (b[i] & (1LL << j)) 62 | b[i] ^= b[j]; 63 | } 64 | } 65 | } 66 | 67 | // need rebuid first 68 | ll queryKth(int k) { 69 | if (k == 1 && tot < n) 70 | return 0; 71 | if (tot < n) 72 | --k; 73 | if (k > (1LL << tot) - 1) 74 | return -1; 75 | ll res = 0; 76 | for (int i = 0; i < B; ++i) { 77 | if (b[i]) { 78 | if (k & 1) 79 | res ^= b[i]; 80 | k >>= 1; 81 | } 82 | } 83 | return res; 84 | } 85 | }; -------------------------------------------------------------------------------- /src/math/Lucas.cpp: -------------------------------------------------------------------------------- 1 | namespace Backlight { 2 | 3 | // use this when n, m is really large and p is small 4 | namespace Lucas { 5 | inline ll pow(ll a, ll b, ll p) { 6 | ll res = 1; 7 | a %= p; 8 | while (b) { 9 | if (b & 1) 10 | res = res * a % p; 11 | a = a * a % p; 12 | b >>= 1; 13 | } 14 | return res; 15 | } 16 | 17 | inline ll inv1(ll n, ll p) { 18 | return pow(n, p - 2, p); 19 | } 20 | 21 | inline ll C1(ll n, ll m, ll p) { 22 | if (m > n) 23 | return 0; 24 | if (m > n - m) 25 | m = n - m; 26 | ll u = 1, d = 1; 27 | for (ll i = 1; i <= m; ++i) { 28 | u = u * (n - i + 1) % p; 29 | d = d * i % p; 30 | } 31 | return u * inv1(d, p) % p; 32 | } 33 | 34 | // solve n choose m (mod p) while p is a prime 35 | ll lucas(ll n, ll m, ll p) { 36 | if (m == 0) 37 | return 1; 38 | return C1(n % p, m % p, p) * lucas(n / p, m / p, p) % p; 39 | } 40 | 41 | ll exgcd(ll a, ll b, ll& x, ll& y) { 42 | if (b == 0) { 43 | x = 1; 44 | y = 0; 45 | return a; 46 | } 47 | ll d = exgcd(b, a % b, x, y); 48 | ll z = x; 49 | x = y; 50 | y = z - y * (a / b); 51 | return d; 52 | } 53 | 54 | inline ll inv2(ll n, ll p) { 55 | ll x, y; 56 | ll d = exgcd(n, p, x, y); 57 | return d == 1 ? (p + x % p) % p : -1; 58 | } 59 | 60 | // n! mod pk without pi^x 61 | ll f(ll n, ll pi, ll pk) { 62 | if (!n) 63 | return 1; 64 | ll res = 1; 65 | if (n / pk) { 66 | for (ll i = 2; i <= pk; ++i) 67 | if (i % pi) 68 | res = res * i % pk; 69 | res = pow(res, n / pk, pk); 70 | } 71 | for (ll i = 2; i <= n % pk; ++i) 72 | if (i % pi) 73 | res = res * i % pk; 74 | return res * f(n / pi, pi, pk) % pk; 75 | } 76 | 77 | ll C2(ll n, ll m, ll p, ll pi, ll pk) { 78 | if (m > n) 79 | return 0; 80 | ll a = f(n, pi, pk), b = f(m, pi, pk), c = f(n - m, pi, pk); 81 | ll k = 0; 82 | for (ll i = n; i; i /= pi) 83 | k += i / pi; 84 | for (ll i = m; i; i /= pi) 85 | k -= i / pi; 86 | for (ll i = n - m; i; i /= pi) 87 | k -= i / pi; 88 | ll ans = a * inv2(b, pk) % pk * inv2(c, pk) % pk * pow(pi, k, pk) % pk; 89 | ans = ans * (p / pk) % p * inv2(p / pk, pk) % p; 90 | return ans; 91 | } 92 | 93 | // solve n choose m (mod p) while p might not be a prime 94 | ll exlucas(ll n, ll m, ll p) { 95 | ll x = p; 96 | ll ans = 0; 97 | for (ll i = 2; i <= p; ++i) { 98 | if (x % i == 0) { 99 | ll pk = 1; 100 | while (x % i == 0) 101 | pk *= i, x /= i; 102 | ans = (ans + C2(n, m, p, i, pk)) % p; 103 | } 104 | } 105 | return ans; 106 | } 107 | 108 | } // namespace Lucas 109 | 110 | } // namespace Backlight -------------------------------------------------------------------------------- /src/math/Matrix.cpp: -------------------------------------------------------------------------------- 1 | template 2 | class Matrix { 3 | private: 4 | using MatrixDataType = std::vector>; 5 | using RowDataType = std::vector; 6 | 7 | int n_; 8 | int m_; 9 | MatrixDataType a_; 10 | 11 | public: 12 | static Matrix zero(int n, int m) { 13 | MatrixDataType data(n, RowDataType(m, 0)); 14 | return Matrix(move(data)); 15 | } 16 | 17 | static Matrix one(int n, int m) { 18 | assert(n == m); 19 | MatrixDataType data(n, RowDataType(m, 0)); 20 | for (int i = 0; i < n; ++i) { 21 | data[i][i] = 1; 22 | } 23 | return Matrix(move(data)); 24 | } 25 | 26 | public: 27 | Matrix() : n_(0), m_(0) {} 28 | 29 | Matrix(const MatrixDataType& a) : n_(a.size()), m_(a[0].size()), a_(a) {} 30 | 31 | Matrix(const Matrix& matrix) : n_(matrix.n_), m_(matrix.m_), a_(matrix.a_) {} 32 | 33 | int n() const { return n_; } 34 | 35 | int m() const { return m_; } 36 | 37 | RowDataType& operator[](int row) { return a_[row]; } 38 | 39 | const ValueType& at(int row, int col) const { return a_[row][col]; } 40 | 41 | friend Matrix operator*(const Matrix& lhs, const Matrix& rhs) { 42 | assert(lhs.m() == rhs.n()); 43 | 44 | Matrix result = zero(lhs.n(), rhs.m()); 45 | for (int i = 0; i < lhs.n(); ++i) { 46 | for (int j = 0; j < lhs.m(); ++j) { 47 | for (int k = 0; k < rhs.m(); ++k) { 48 | result[i][k] = result.at(i, k) + lhs.at(i, j) * rhs.at(j, k); 49 | } 50 | } 51 | } 52 | return result; 53 | } 54 | 55 | void operator=(const Matrix& rhs) { 56 | n_ = rhs.n_; 57 | m_ = rhs.m_; 58 | a_ = rhs.a_; 59 | } 60 | 61 | friend Matrix operator^(const Matrix& lhs, int64_t exponent) { 62 | assert(lhs.n() == lhs.m()); 63 | 64 | Matrix result = one(lhs.n(), lhs.m()); 65 | Matrix base = lhs; 66 | while (exponent) { 67 | if (exponent & 1) 68 | result = result * base; 69 | base = base * base; 70 | exponent >>= 1; 71 | } 72 | return result; 73 | } 74 | 75 | std::string to_string() const { 76 | std::stringstream ss; 77 | ss << "["; 78 | for (int i = 0; i < n_; ++i) { 79 | ss << "["; 80 | for (int j = 0; j < m_; ++j) { 81 | ss << a_[i][j].value() << ",]"[j == m_ - 1]; 82 | } 83 | ss << ",]"[i == n_ - 1]; 84 | } 85 | return ss.str(); 86 | } 87 | }; -------------------------------------------------------------------------------- /src/math/Mobius.cpp: -------------------------------------------------------------------------------- 1 | int primes[N], pcnt; 2 | bool is[N]; 3 | int mu[N]; // 莫比乌斯函数,在这里是其前缀和 4 | void seive() { 5 | pcnt = 0; 6 | mu[1] = 1; 7 | for (int i = 2; i < N; ++i) 8 | is[i] = true; 9 | for (int i = 2; i < N; ++i) { 10 | if (is[i]) 11 | primes[++pcnt] = i, mu[i] = -1; 12 | for (int j = 1; j <= pcnt; ++j) { 13 | ll nxt = 1ll * i * primes[j]; 14 | if (nxt >= N) 15 | break; 16 | is[nxt] = false; 17 | if (i % primes[j] == 0) { 18 | mu[nxt] = 0; 19 | break; 20 | } 21 | mu[nxt] = -mu[i]; 22 | } 23 | } 24 | for (int i = 1; i < N; ++i) 25 | mu[i] += mu[i - 1]; 26 | } -------------------------------------------------------------------------------- /src/math/Modular.cpp: -------------------------------------------------------------------------------- 1 | const int MOD = 1e9 + 7; 2 | int add(int x, int y) { 3 | return x + y >= MOD ? x + y - MOD : x + y; 4 | } 5 | int mul(int x, int y) { 6 | return 1ll * x * y % MOD; 7 | } 8 | int sub(int x, int y) { 9 | return x - y < 0 ? x - y + MOD : x - y; 10 | } 11 | int qp(int x, int y) { 12 | int r = 1; 13 | while (y) { 14 | if (y & 1) 15 | r = mul(r, x); 16 | x = mul(x, x); 17 | y >>= 1; 18 | } 19 | return r; 20 | } 21 | int inv(int x) { 22 | return qp(x, MOD - 2); 23 | } 24 | int dvd(int x, int y) { 25 | return mul(x, inv(y)); 26 | } -------------------------------------------------------------------------------- /src/math/Modular2.cpp: -------------------------------------------------------------------------------- 1 | template 2 | class Modular { 3 | static ValueType normalize(ValueType value) { 4 | if (value >= 0 && value < mod_) 5 | return value; 6 | value %= mod_; 7 | if (value < 0) 8 | value += mod_; 9 | return value; 10 | } 11 | 12 | template 13 | static ValueType power(ValueType value, ExponentType exponent) { 14 | ValueType result = 1; 15 | ValueType base = value; 16 | while (exponent) { 17 | if (exponent & 1) 18 | result = SupperType(result) * base % mod_; 19 | base = SupperType(base) * base % mod_; 20 | exponent >>= 1; 21 | } 22 | return result; 23 | } 24 | 25 | public: 26 | Modular() : value_(0) {} 27 | 28 | Modular(ValueType value) : value_(normalize(value)) {} 29 | 30 | Modular(SupperType value) : value_(normalize(value % mod_)) {} 31 | 32 | ValueType value() const { return value_; } 33 | 34 | Modular inv() const { return Modular(power(value_, mod_ - 2)); } 35 | 36 | template 37 | Modular power(ExponentType exponent) const { 38 | return Modular(power(value_, exponent)); 39 | } 40 | 41 | Modular operator-() const { return Modular(mod_ - value_); } 42 | 43 | Modular& operator+=(const Modular& other) { 44 | value_ = value_ + other.value() >= mod_ ? value_ + other.value() - mod_ 45 | : value_ + other.value(); 46 | return (*this); 47 | } 48 | 49 | Modular& operator-=(const Modular& other) { 50 | value_ = value_ - other.value() < 0 ? value_ - other.value() + mod_ 51 | : value_ - other.value(); 52 | return (*this); 53 | } 54 | 55 | Modular& operator*=(const Modular& other) { 56 | value_ = SupperType(1) * value_ * other.value() % mod_; 57 | return (*this); 58 | } 59 | 60 | Modular& operator/=(const Modular& other) { 61 | value_ = SupperType(1) * value_ * other.inv().value() % mod_; 62 | return (*this); 63 | } 64 | 65 | Modular operator+(const Modular& other) const { 66 | Modular result = *this; 67 | result += other; 68 | return result; 69 | } 70 | 71 | Modular operator-(const Modular& other) const { 72 | Modular result = *this; 73 | result -= other; 74 | return result; 75 | } 76 | 77 | Modular operator*(const Modular& other) const { 78 | Modular result = *this; 79 | result *= other; 80 | return result; 81 | } 82 | 83 | Modular operator/(const Modular& other) const { 84 | Modular result = *this; 85 | result /= other; 86 | return result; 87 | } 88 | 89 | std::string to_string() const { return std::to_string(value_); } 90 | 91 | private: 92 | ValueType value_; 93 | }; 94 | 95 | // using Mint = Modular; 96 | using Mint = Modular; 97 | 98 | class Binom { 99 | public: 100 | std::vector f, g; 101 | 102 | public: 103 | Binom(int n) { 104 | f.resize(n + 1); 105 | g.resize(n + 1); 106 | 107 | f[0] = Mint(1); 108 | for (int i = 1; i <= n; ++i) 109 | f[i] = f[i - 1] * Mint(i); 110 | g[n] = f[n].inv(); 111 | for (int i = n - 1; i >= 0; --i) 112 | g[i] = g[i + 1] * Mint(i + 1); 113 | } 114 | Mint operator()(int n, int m) { 115 | if (n < 0 || m < 0 || m > n) 116 | return Mint(0); 117 | return f[n] * g[m] * g[n - m]; 118 | } 119 | }; -------------------------------------------------------------------------------- /src/math/NTT.cpp: -------------------------------------------------------------------------------- 1 | namespace Backlight { 2 | 3 | namespace NTT { 4 | // 998244353, 1004535809 5 | const int P = 998244353, G = 3, Gi = 332748118; 6 | 7 | inline ll pow(ll a, ll b) { 8 | ll res = 1; 9 | a %= P; 10 | while (b) { 11 | if (b & 1) 12 | res = res * a % P; 13 | a = a * a % P; 14 | b >>= 1; 15 | } 16 | return res; 17 | } 18 | 19 | int N, L; 20 | vector r; 21 | void init(vector& a, vector& b) { 22 | int l = a.size() + b.size(); 23 | N = 1; 24 | L = 0; 25 | while (N < l) 26 | N <<= 1, ++L; 27 | a.resize(N); 28 | b.resize(N); 29 | r.resize(N); 30 | for (int i = 0; i < N; ++i) 31 | r[i] = (r[i >> 1] >> 1) | ((i & 1) << (L - 1)); 32 | } 33 | 34 | void work(vector& a, int flag) { 35 | for (int i = 0; i < N; i++) 36 | if (i < r[i]) 37 | swap(a[i], a[r[i]]); 38 | for (int mid = 1; mid < N; mid <<= 1) { 39 | ll wn = pow(flag == 1 ? G : Gi, (P - 1) / (mid << 1)); 40 | for (int j = 0; j < N; j += (mid << 1)) { 41 | ll w = 1; 42 | for (int k = 0; k < mid; k++, w = (w * wn) % P) { 43 | int x = a[j + k], y = w * a[j + k + mid] % P; 44 | a[j + k] = (x + y) % P, 45 | a[j + k + mid] = (x - y + P) % P; 46 | } 47 | } 48 | } 49 | } 50 | 51 | inline void NTT(vector& a) { 52 | work(a, 1); 53 | } 54 | inline void INTT(vector& a) { 55 | work(a, -1); 56 | } 57 | 58 | vector convolution(vector a, vector b) { 59 | init(a, b); 60 | NTT(a); 61 | NTT(b); 62 | for (int i = 0; i < N; ++i) 63 | a[i] = a[i] * b[i] % P; 64 | INTT(a); 65 | ll inv = pow(N, P - 2); 66 | for (int i = 0; i < N; ++i) 67 | a[i] = a[i] * inv % P; 68 | return a; 69 | } 70 | } // namespace NTT 71 | 72 | } // namespace Backlight -------------------------------------------------------------------------------- /src/math/PollardRho.cpp: -------------------------------------------------------------------------------- 1 | // Problem: P4718 【模板】Pollard-Rho算法 2 | // Contest: Luogu 3 | // URL: https://www.luogu.com.cn/problem/P4718 4 | // Memory Limit: 125 MB 5 | // Time Limit: 2000 ms 6 | // 7 | // Powered by CP Editor (https://cpeditor.org) 8 | 9 | #include 10 | 11 | #define CPPIO std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0); 12 | #define freep(p) p ? delete p, p = nullptr, void(1) : void(0) 13 | 14 | #ifdef BACKLIGHT 15 | #include "debug.h" 16 | #else 17 | #define logd(...) ; 18 | #endif 19 | 20 | using i64 = int64_t; 21 | using u64 = uint64_t; 22 | using i128 = __int128_t; 23 | 24 | void solve_case(int Case); 25 | 26 | int main(int argc, char* argv[]) { 27 | CPPIO; 28 | int T = 1; 29 | std::cin >> T; 30 | for (int t = 1; t <= T; ++t) { 31 | solve_case(t); 32 | } 33 | return 0; 34 | } 35 | 36 | namespace PollardRho { 37 | 38 | /** 39 | * @TODO: __int128_t is ugly, try optimize it. 40 | */ 41 | 42 | static std::mt19937_64 rng_(std::chrono::steady_clock::now().time_since_epoch().count()); 43 | 44 | inline int64_t Rand(int64_t l, int64_t r) { 45 | return l + rng_() % (r - l + 1); 46 | } 47 | 48 | inline int64_t Add(int64_t a, int64_t b, int64_t mod) { 49 | return ((__int128_t)a + b) % mod; 50 | } 51 | 52 | inline int64_t Substract(int64_t a, int64_t b, int64_t mod) { 53 | return (((__int128_t)a - b) % mod + mod) % mod; 54 | } 55 | 56 | inline int64_t Multiply(int64_t a, int64_t b, int64_t mod) { 57 | return (__int128_t)a * b % mod; 58 | } 59 | 60 | inline int64_t Power(int64_t a, int64_t b, int64_t mod) { 61 | int64_t r = 1; 62 | while (b) { 63 | if (b & 1) 64 | r = Multiply(r, a, mod); 65 | a = Multiply(a, a, mod); 66 | b >>= 1; 67 | } 68 | return r; 69 | } 70 | 71 | // Time Complexity: $O(k \log^{3} n)$ 72 | bool MillerRabinTest(int64_t n) { 73 | // Strong enough for $n < 2^64$, see https://oeis.org/A014233. 74 | constexpr static int kTestRounds = 12; 75 | constexpr static int kTestBase[kTestRounds] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37}; 76 | 77 | if (n <= kTestBase[kTestRounds - 1]) { 78 | return *std::lower_bound(kTestBase, kTestBase + kTestRounds, n) == n; 79 | } 80 | 81 | int64_t d = n - 1, r = 0; 82 | while (d % 2 == 0) { 83 | d >>= 1; 84 | r = r + 1; 85 | } 86 | 87 | for (int round = 0; round < kTestRounds; ++round) { 88 | int64_t a = kTestBase[round]; 89 | 90 | // Fermet primality test. 91 | int64_t x = Power(a, d, n); 92 | if (x == 1 || x == n - 1) 93 | continue; 94 | 95 | // Witness primality test. 96 | for (int i = 0; i < r - 1; ++i) { 97 | x = Multiply(x, x, n); 98 | if (x == n - 1) 99 | break; 100 | } 101 | if (x != n - 1) 102 | return false; 103 | } 104 | 105 | return true; 106 | } 107 | 108 | int64_t Rho(int64_t n) { 109 | // Can not factor 4 because the faster step gap is 2. 110 | if (n == 4) 111 | return 2; 112 | 113 | const static int kMaxStepSize = 1 << 7; 114 | 115 | int64_t c; 116 | std::function f = [&n, &c](int64_t x) { return Add(Multiply(x, x, n), c, n); }; 117 | 118 | // Since n is not a prime, there must be a non-trivial factor of n. 119 | for (;;) { 120 | /** 121 | * Brent's cycle finding method, and replace k gcd steps with k - 1 multiplications 122 | * modulo n and a single gcd. 123 | * reference: https://en.wikipedia.org/wiki/Pollard%27s_rho_algorithm#Variants. 124 | */ 125 | c = Rand(3, n - 1); 126 | 127 | int64_t x = Rand(0, n - 1); 128 | int64_t t = f(x), r = f(t); 129 | int64_t goal = 1, curr = 1; 130 | int64_t d1, d2 = 1; 131 | while (t != r) { 132 | d1 = Multiply(d2, std::abs(r - t), n); 133 | if (d1 == 0) { 134 | break; 135 | } else { 136 | d2 = d1; 137 | } 138 | 139 | if (curr % kMaxStepSize == 0) { 140 | int64_t d = std::gcd(d2, n); 141 | if (d != 1 && d != n) 142 | return d; 143 | } 144 | 145 | if (curr == goal) { 146 | int64_t d = std::gcd(d2, n); 147 | if (d != 1 && d != n) 148 | return d; 149 | 150 | t = r; 151 | goal = goal * 2; 152 | curr = 0; 153 | } 154 | 155 | r = f(r); 156 | ++curr; 157 | } 158 | } 159 | } 160 | 161 | std::vector Factor(int64_t n) { 162 | std::vector factors; 163 | std::function factor = [&](int64_t n) { 164 | if (n < 2) 165 | return; 166 | 167 | if (MillerRabinTest(n)) { 168 | factors.push_back(n); 169 | } else { 170 | int64_t x = Rho(n); 171 | while (n % x == 0) 172 | n /= x; 173 | factor(x); 174 | factor(n); 175 | } 176 | }; 177 | factor(n); 178 | std::sort(factors.begin(), factors.end()); 179 | return factors; 180 | } 181 | 182 | }; // namespace PollardRho 183 | 184 | void solve_case(int Case) { 185 | int64_t n; 186 | std::cin >> n; 187 | auto f = PollardRho::Factor(n); 188 | 189 | if (f.size() == 1 and n == f.back()) 190 | std::cout << "Prime\n"; 191 | else 192 | std::cout << f.back() << "\n"; 193 | } -------------------------------------------------------------------------------- /src/math/PowerfulNumber.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | using ll = int64_t; 4 | 5 | constexpr int MOD = 1e9 + 7; // 998244353 1e9 + 7 6 | template 7 | inline int mint(T x) { 8 | x %= MOD; 9 | if (x < 0) 10 | x += MOD; 11 | return x; 12 | } 13 | inline int add(int x, int y) { 14 | return x + y >= MOD ? x + y - MOD : x + y; 15 | } 16 | inline int mul(int x, int y) { 17 | return 1ll * x * y % MOD; 18 | } 19 | inline int sub(int x, int y) { 20 | return x < y ? x - y + MOD : x - y; 21 | } 22 | inline int qp(int x, int y) { 23 | int r = 1; 24 | for (; y; y >>= 1) { 25 | if (y & 1) 26 | r = mul(r, x); 27 | x = mul(x, x); 28 | } 29 | return r; 30 | } 31 | inline int inv(int x) { 32 | return qp(x, MOD - 2); 33 | } 34 | 35 | namespace PNS { 36 | const int N = 2e6 + 5; 37 | const int M = 35; 38 | 39 | ll global_n; 40 | 41 | int g[N], sg[N]; 42 | 43 | int h[N][M]; 44 | bool vis_h[N][M]; 45 | 46 | int ans; 47 | 48 | int pcnt, prime[N], phi[N]; 49 | bool isp[N]; 50 | 51 | void sieve(int n) { 52 | pcnt = 0; 53 | for (int i = 2; i <= n; ++i) 54 | isp[i] = true; 55 | phi[1] = 1; 56 | for (int i = 2; i <= n; ++i) { 57 | if (isp[i]) { 58 | ++pcnt; 59 | prime[pcnt] = i; 60 | phi[i] = i - 1; 61 | } 62 | for (int j = 1; j <= pcnt; ++j) { 63 | ll nxt = 1ll * i * prime[j]; 64 | if (nxt > n) 65 | break; 66 | isp[nxt] = false; 67 | if (i % prime[j] == 0) { 68 | phi[nxt] = phi[i] * prime[j]; 69 | break; 70 | } 71 | phi[nxt] = phi[i] * phi[prime[j]]; 72 | } 73 | } 74 | 75 | for (int i = 1; i <= n; ++i) 76 | g[i] = mul(i, phi[i]); 77 | 78 | sg[0] = 0; 79 | for (int i = 1; i <= n; ++i) 80 | sg[i] = add(sg[i - 1], g[i]); 81 | } 82 | 83 | int inv2, inv6; 84 | void init() { 85 | sieve(N - 1); 86 | for (int i = 1; i <= pcnt; ++i) 87 | h[i][0] = 1, h[i][1] = 0; 88 | for (int i = 1; i <= pcnt; ++i) 89 | vis_h[i][0] = vis_h[i][1] = true; 90 | inv2 = inv(2); 91 | inv6 = inv(6); 92 | } 93 | 94 | int S1(ll n) { 95 | return mul(mul(mint(n), mint(n + 1)), inv2); 96 | } 97 | 98 | int S2(ll n) { 99 | return mul(mul(mint(n), mul(mint(n + 1), mint(n * 2 + 1))), inv6); 100 | } 101 | 102 | map mp_g; 103 | 104 | int G(ll n) { 105 | if (n < N) 106 | return sg[n]; 107 | if (mp_g.count(n)) 108 | return mp_g[n]; 109 | 110 | int ret = S2(n); 111 | for (ll i = 2, j; i <= n; i = j + 1) { 112 | j = n / (n / i); 113 | ret = sub(ret, mul(sub(S1(j), S1(i - 1)), G(n / i))); 114 | } 115 | mp_g[n] = ret; 116 | return ret; 117 | } 118 | 119 | void dfs(ll d, int hd, int pid) { 120 | ans = add(ans, mul(hd, G(global_n / d))); 121 | 122 | for (int i = pid, p; i <= pcnt; ++i) { 123 | if (i > 1 && d > global_n / prime[i] / prime[i]) 124 | break; 125 | 126 | int c = 2; 127 | for (ll x = d * prime[i] * prime[i]; x <= global_n; x *= prime[i], ++c) { 128 | if (!vis_h[i][c]) { 129 | int f = qp(prime[i], c); 130 | f = mul(f, sub(f, 1)); 131 | int g = mul(prime[i], prime[i] - 1); 132 | int t = mul(prime[i], prime[i]); 133 | 134 | for (int j = 1; j <= c; ++j) { 135 | f = sub(f, mul(g, h[i][c - j])); 136 | g = mul(g, t); 137 | } 138 | h[i][c] = f; 139 | vis_h[i][c] = true; 140 | } 141 | 142 | if (h[i][c]) 143 | dfs(x, mul(hd, h[i][c]), i + 1); 144 | } 145 | } 146 | } 147 | 148 | int solve(ll n) { 149 | global_n = n; 150 | ans = 0; 151 | dfs(1, 1, 1); 152 | return ans; 153 | } 154 | } // namespace PNS 155 | 156 | int main() { 157 | PNS::init(); 158 | ll n; 159 | scanf("%lld", &n); 160 | printf("%d\n", PNS::solve(n)); 161 | return 0; 162 | } -------------------------------------------------------------------------------- /src/math/Simplex.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Simplex Alogorithm: 3 | * solve $\max z = \sum_{j = 1}^{n} c_{j}x_{j}$ 4 | * with restrictions like: $ \sum_{j = 1}^{n} a_{ij}x_{j} = b_{j}, i = 1, 2, ..., m $ 5 | * $ x_j \ge 0 $ 6 | * in $ O(knm) $, where k is a const number。 7 | * 8 | * Tips: 1. min => -min => max 9 | * 2. $x_1 + 2x_2 \le 9$ => $ x_1 + x_2 + x_3 = 9, x_3 \ge 0 $ 10 | * 3. x_k without restrictions => $x_k = x_m - x_m and x_m, x_n \ge 0$ 11 | * 12 | * Notes: 1. c = A_{0} 13 | * 2. z = max cx 14 | * 3. Ax = b 15 | */ 16 | enum { 17 | OK = 1, 18 | UNBOUNDED = 2, 19 | INFEASIBLE = 3 20 | }; 21 | struct Simplex { 22 | constexpr static double eps = 1e-10; 23 | 24 | int n, m; 25 | int flag; 26 | double z; 27 | vector> A; 28 | vector b, x; 29 | vector idx, idy; 30 | 31 | Simplex(int _n, int _m) 32 | : n(_n), m(_m) { 33 | A = vector>(m + 1, vector(n + 1)); 34 | b = vector(m + 1); 35 | x = vector(n + 1); 36 | idx = vector(m + 1); 37 | idy = vector(n + 1); 38 | } 39 | 40 | void input() { 41 | for (int i = 1; i <= n; ++i) 42 | read(A[0][i]); // A_{0,i} = c_i 43 | for (int i = 1; i <= m; ++i) { 44 | for (int j = 1; j <= n; ++j) 45 | read(A[i][j]); 46 | read(b[i]); 47 | } 48 | } 49 | 50 | void pivot(int x, int y) { 51 | swap(idx[x], idy[y]); 52 | 53 | double k = A[x][y]; 54 | for (int i = 1; i <= n; ++i) 55 | A[x][i] /= k; 56 | b[x] /= k; 57 | A[x][y] = 1 / k; 58 | 59 | for (int i = 0; i <= m; ++i) 60 | if (i != x) { 61 | k = A[i][y]; 62 | b[i] -= k * b[x]; 63 | A[i][y] = 0; 64 | for (int j = 1; j <= n; ++j) 65 | A[i][j] -= k * A[x][j]; 66 | } 67 | } 68 | 69 | void init() { 70 | flag = OK; 71 | idx[0] = INT_MAX; 72 | for (int i = 1; i <= m; ++i) 73 | idx[i] = n + i; 74 | idy[0] = INT_MAX; 75 | for (int i = 1; i <= n; ++i) 76 | idy[i] = i; 77 | 78 | for (;;) { 79 | int x = 0, y = 0; 80 | for (int i = 1; i <= m; ++i) 81 | if (b[i] < -eps && idx[i] < idx[x]) 82 | x = i; 83 | if (!x) 84 | break; 85 | 86 | for (int i = 1; i <= n; ++i) 87 | if (A[x][i] < -eps && idy[i] < idy[y]) 88 | y = i; 89 | if (!y) { 90 | flag = INFEASIBLE; 91 | break; 92 | } 93 | 94 | pivot(x, y); 95 | } 96 | } 97 | 98 | void simplex() { 99 | for (;;) { 100 | int x = 0, y = 0; 101 | for (int i = 1; i <= n; ++i) 102 | if (A[0][i] > eps && idy[i] < idy[y]) 103 | y = i; 104 | if (!y) 105 | break; 106 | 107 | for (int i = 1; i <= m; ++i) 108 | if (A[i][y] > eps) { 109 | if (!x) 110 | x = i; 111 | else { 112 | double delta = b[i] / A[i][y] - b[x] / A[x][y]; 113 | if (delta < -eps) 114 | x = i; 115 | else if (delta < eps && idx[i] < idx[x]) 116 | x = i; 117 | } 118 | } 119 | if (!x) { 120 | flag = UNBOUNDED; 121 | break; 122 | } 123 | 124 | pivot(x, y); 125 | } 126 | z = -b[0]; 127 | } 128 | 129 | void work() { 130 | init(); 131 | if (flag == OK) 132 | simplex(); 133 | if (flag == OK) { 134 | for (int i = 1; i <= n; ++i) { 135 | x[i] = 0; 136 | for (int j = 1; j <= m; ++j) 137 | if (idx[j] == i) { 138 | x[i] = b[j]; 139 | break; 140 | } 141 | } 142 | } 143 | } 144 | 145 | void DEBUG() { 146 | cerr << fixed << setprecision(3); 147 | cerr << "Simplex Debug: \n"; 148 | for (int i = 1; i <= m; ++i) { 149 | for (int j = 1; j <= n; ++j) { 150 | cerr << A[i][j] << " "; 151 | } 152 | cerr << "\n"; 153 | } 154 | for (int i = 1; i <= n; ++i) 155 | cerr << x[i] << " "; 156 | cerr << endl; 157 | cerr << "Z = " << z << endl; 158 | } 159 | }; -------------------------------------------------------------------------------- /src/math/SimpsonIntegral.cpp: -------------------------------------------------------------------------------- 1 | namespace SimpsonIntegral { 2 | // calculate \int_l^r f(x) dx 3 | 4 | double f(double x) { 5 | return (c * x + d) / (a * x + b); 6 | } 7 | 8 | double simpson(double l, double r) { 9 | double mid = (l + r) / 2; 10 | return (r - l) * (f(l) + 4 * f(mid) + f(r)) / 6; 11 | } 12 | 13 | double integral(double l, double r, double eps, double ans) { 14 | double mid = (l + r) / 2; 15 | double fl = simpson(l, mid), fr = simpson(mid, r); 16 | if (abs(fl + fr - ans) <= 15 * eps) 17 | return fl + fr + (fl + fr - ans) / 15; 18 | return integral(l, mid, eps / 2, fl) + integral(mid, r, eps / 2, fr); 19 | } 20 | 21 | double integral(double l, double r, double eps = 1e-8) { 22 | return integral(l, r, eps, simpson(l, r)); 23 | } 24 | } // namespace SimpsonIntegral -------------------------------------------------------------------------------- /src/math/du.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | using ll = int64_t; 5 | 6 | const int LIM = 1e7; 7 | 8 | int pcnt, prime[LIM], mu[LIM]; 9 | bool vis[LIM]; 10 | void seive(int n) { 11 | pcnt = 0; 12 | mu[0] = 0; 13 | mu[1] = 1; 14 | for (int i = 2; i <= n; ++i) { 15 | if (!vis[i]) { 16 | prime[++pcnt] = i; 17 | mu[i] = -1; 18 | } 19 | for (int j = 1; j <= pcnt; ++j) { 20 | ll nxt = 1ll * i * prime[j]; 21 | if (nxt > n) 22 | break; 23 | vis[nxt] = true; 24 | if (i % prime[j] == 0) { 25 | mu[nxt] = 0; 26 | break; 27 | } 28 | mu[nxt] = -mu[i]; 29 | } 30 | } 31 | for (int i = 1; i <= n; ++i) 32 | mu[i] += mu[i - 1]; 33 | } 34 | 35 | map mp; 36 | 37 | // $ S(n) = 1 - \sum_{i=2} S(\lfloor \frac{n}{i} \rfloor) $ 38 | // Time Complexity: $O(n^{\frac{2}{3}})$ 39 | ll S_mu(ll n) { 40 | if (n < LIM) 41 | return mu[n]; 42 | if (mp.count(n)) 43 | return mp[n]; 44 | 45 | ll ret = 0; 46 | for (ll i = 2, j; i <= n; i = j + 1) { 47 | j = n / (n / i); 48 | ret += (j - i + 1) * S_mu(n / i); 49 | } 50 | ret = 1 - ret; 51 | 52 | mp[n] = ret; 53 | return ret; 54 | } 55 | 56 | // $ S(n) = \frac{(n + 1)n}{2} - \sum_{i=2}^{n} S(\lfloor \frac{n}{i} \rfloor) $ 57 | // $ S(n) = \sum_{d=1}^{n} \mu(d) \lfloor \frac{n}{d} \rfloor \lfloor \frac{n}{d} \rfloor$ 58 | ll S_phi(ll n) { 59 | ll ret = 0; 60 | for (ll i = 1, j; i <= n; i = j + 1) { 61 | j = n / (n / i); 62 | ret += (S_mu(j) - S_mu(i - 1)) * (n / i) * (n / i); 63 | } 64 | ret = (ret - 1) / 2 + 1; 65 | return ret; 66 | } 67 | 68 | void solve(int Case) { 69 | ll n; 70 | scanf("%lld", &n); 71 | printf("%lld %lld\n", S_phi(n), S_mu(n)); 72 | } 73 | 74 | int main() { 75 | seive(LIM - 1); 76 | int T = 1; 77 | scanf("%d", &T); 78 | for (int _ = 1; _ <= T; _++) 79 | solve(_); 80 | return 0; 81 | } -------------------------------------------------------------------------------- /src/math/eval.cpp: -------------------------------------------------------------------------------- 1 | int pri(char c) { 2 | if (c == '^') 3 | return 3; 4 | if (c == '*' || c == '/') 5 | return 2; 6 | if (c == '+' || c == '-') 7 | return 1; 8 | return 0; 9 | } 10 | 11 | void in2post(char* s, char* t) { 12 | int n = strlen(s), j = 0; 13 | stack ops; 14 | for (int i = 0; i < n; ++i) { 15 | t[j] = 0; 16 | if (islower(s[i])) { 17 | while (i < n && isdigit(s[i])) { 18 | t[j++] = s[i++]; 19 | } 20 | t[j++] = ' '; 21 | --i; 22 | } else if (s[i] == '(') { 23 | ops.push('('); 24 | } else if (s[i] == ')') { 25 | char op = 0; 26 | while (!ops.empty()) { 27 | op = ops.top(); 28 | ops.pop(); 29 | if (op == '(') 30 | break; 31 | t[j++] = op; 32 | t[j++] = ' '; 33 | } 34 | assert(op == '('); 35 | } else { 36 | while (!ops.empty() && pri(s[i]) <= pri(ops.top())) { 37 | t[j++] = ops.top(); 38 | t[j++] = ' '; 39 | ops.pop(); 40 | } 41 | ops.push(s[i]); 42 | } 43 | } 44 | while (!ops.empty()) { 45 | assert(ops.top() != '('); 46 | t[j++] = ops.top(); 47 | t[j++] = ' '; 48 | ops.pop(); 49 | } 50 | t[j] = 0; 51 | } 52 | 53 | int eval(char* s) { 54 | int n = strlen(s); 55 | stack nums; 56 | for (int i = 0; i < n; ++i) { 57 | if (isdigit(s[i])) { 58 | int num = 0; 59 | while (i < n && isdigit(s[i])) { 60 | num = num * 10 + s[i++] - '0'; 61 | } 62 | nums.push(num); 63 | --i; 64 | continue; 65 | } 66 | 67 | if (s[i] == ' ') 68 | continue; 69 | 70 | assert(nums.size() >= 2); 71 | int num2 = nums.top(); 72 | nums.pop(); 73 | int num1 = nums.top(); 74 | nums.pop(); 75 | switch (s[i]) { 76 | case '+': 77 | nums.push(num1 + num2); 78 | break; 79 | case '-': 80 | nums.push(num1 - num2); 81 | break; 82 | case '*': 83 | nums.push(num1 * num2); 84 | break; 85 | case '/': 86 | nums.push(num1 / num2); 87 | break; 88 | default: 89 | assert(false); 90 | break; 91 | } 92 | } 93 | assert(nums.size() == 1); 94 | return nums.top(); 95 | } -------------------------------------------------------------------------------- /src/math/min25.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | using ll = int64_t; 5 | 6 | const int MOD = 1e9 + 7; 7 | 8 | template 9 | inline int mint(T x) { 10 | x %= MOD; 11 | if (x < 0) 12 | x += MOD; 13 | return x; 14 | } 15 | inline int add(int x, int y) { 16 | return x + y >= MOD ? x + y - MOD : x + y; 17 | } 18 | inline int mul(int x, int y) { 19 | return 1ll * x * y % MOD; 20 | } 21 | inline int sub(int x, int y) { 22 | return x < y ? x - y + MOD : x - y; 23 | } 24 | inline int qp(int x, int y) { 25 | int r = 1; 26 | for (; y; y >>= 1) { 27 | if (y & 1) 28 | r = mul(r, x); 29 | x = mul(x, x); 30 | } 31 | return r; 32 | } 33 | inline int inv(int x) { 34 | return qp(x, MOD - 2); 35 | } 36 | inline int dvd(int x, int y) { 37 | return 1ll * x * qp(y, MOD - 2) % MOD; 38 | } 39 | inline void inc(int& x, int y) { 40 | x += y; 41 | if (x >= MOD) 42 | x -= MOD; 43 | } 44 | inline void dec(int& x, int y) { 45 | x -= y; 46 | if (x < 0) 47 | x += MOD; 48 | } 49 | 50 | namespace min25 { 51 | /* 52 | calc the prefix sum of multiplicative function. 53 | Requirements: 54 | Assume $p$ is a prime number. 55 | 1. $f(p)$ is a polynomial with small deg or can be calc quickly. 56 | 2. $f(p^e)$ can be calc quickly. 57 | Time complexity: $O(\frac{n^{0.75}}{\log n})$ 58 | Steps: assume $deg(f(p)) = n$. 59 | 1. split $f(p)$ into $n$ parts by it exponent. 60 | 2. calc them separately. 61 | 3. then sum them up. 62 | e.g.: $f(p) = \phi(p) = p - 1$ 63 | 1. calc $ans_0$ for $f(p) = p$. 64 | 2. calc $ans_1$ for $f(p) = 1$. 65 | 3. $ans = ans_0 - ans_1$. 66 | */ 67 | const int LIM = 2e5 + 9; 68 | 69 | ll gn, w[LIM]; 70 | int rt, lim, id1[LIM], id2[LIM]; 71 | #define idx(v) (v <= rt ? id1[v] : id2[gn / v]) 72 | 73 | int pcnt, prime[LIM]; 74 | bool isp[LIM]; 75 | 76 | // $ sp_{i, j} = \sum_{k=1}^j [\text{p is a prime}]p^{i} $ 77 | int sp1[LIM]; 78 | 79 | void seive(const int& n) { 80 | pcnt = 0; 81 | fill(isp, isp + n + 1, true); 82 | for (int i = 2; i <= n; ++i) { 83 | if (isp[i]) { 84 | ++pcnt; 85 | prime[pcnt] = i; 86 | } 87 | for (int j = 1; j <= pcnt; ++j) { 88 | ll nxt = 1ll * i * prime[j]; 89 | if (nxt > n) 90 | break; 91 | isp[nxt] = false; 92 | if (i % prime[j] == 0) 93 | break; 94 | } 95 | } 96 | for (int i = 1; i <= pcnt; ++i) 97 | sp1[i] = add(sp1[i - 1], prime[i]); 98 | } 99 | 100 | int G[LIM][2], H[LIM]; 101 | 102 | void initG0(const ll& n) { 103 | lim = 0; 104 | int inv2 = inv(2); 105 | for (ll i = 1, j, v; i <= n; i = n / j + 1) { 106 | j = n / i; 107 | 108 | w[++lim] = j; 109 | idx(j) = lim; 110 | 111 | v = j % MOD; 112 | 113 | // init $G_0 = \sum_{i=2}^n g(i)$ 114 | G[lim][0] = sub(v, 1); 115 | G[lim][1] = mul(mul(mint(v + 2), mint(v - 1)), inv2); 116 | } 117 | } 118 | 119 | void calcH() { 120 | for (int k = 1; k <= pcnt; ++k) { 121 | const int p = prime[k]; 122 | const ll p2 = 1ll * p * p; 123 | for (int i = 1; w[i] >= p2; ++i) { 124 | const ll v = w[i] / p; 125 | int id = idx(v); 126 | dec(G[i][0], sub(G[id][0], k - 1)); 127 | dec(G[i][1], mul(p, sub(G[id][1], sp1[k - 1]))); 128 | } 129 | } 130 | for (int i = 1; i <= lim; ++i) 131 | H[i] = sub(G[i][1], G[i][0]); 132 | } 133 | 134 | // $f(p^{e})$ 135 | inline int fpe(const int& p, const int& e) { 136 | return p xor e; 137 | } 138 | 139 | int F(const int& k, const ll& n) { 140 | if (n < prime[k] || n <= 1) 141 | return 0; 142 | 143 | int r1 = 0; 144 | for (int i = k; i <= pcnt; ++i) { 145 | ll pi = prime[i]; 146 | if (1ll * pi * pi > n) 147 | break; 148 | ll pc = pi, pc2 = pi * pi; 149 | for (int c = 1; pc2 <= n; ++c) { 150 | inc(r1, add(mul(fpe(pi, c), F(i + 1, n / pc)), fpe(pi, c + 1))); 151 | pc = pc2; 152 | pc2 = pc2 * pi; 153 | } 154 | } 155 | 156 | // $H(n) - H(p_{k-1})$ 157 | const int id = idx(n); 158 | int r2 = sub(H[id], sub(sp1[k - 1], k - 1)); 159 | if (k == 1) 160 | inc(r2, 2); 161 | int ans = add(r1, r2); 162 | return ans; 163 | } 164 | 165 | int solve(ll n) { 166 | gn = n; 167 | rt = sqrt(gn); 168 | seive(rt + 5); 169 | initG0(gn); 170 | calcH(); 171 | return add(F(1, n), 1); 172 | } 173 | } // namespace min25 174 | 175 | int main() { 176 | ll n; 177 | scanf("%lld", &n); 178 | printf("%d\n", min25::solve(n)); 179 | return 0; 180 | } -------------------------------------------------------------------------------- /src/misc/STLWrapper.cpp: -------------------------------------------------------------------------------- 1 | namespace STLWrapper { 2 | 3 | template 4 | auto n_vector(size_t n, Args&&... args) { 5 | if constexpr (sizeof...(args) == 1) { 6 | return std::vector(n, args...); 7 | } else { 8 | return std::vector(n, n_vector(args...)); 9 | } 10 | } 11 | 12 | template 13 | using min_heap = std::priority_queue, std::greater>; 14 | 15 | template 16 | using max_heap = std::priority_queue, std::less>; 17 | 18 | } // namespace STLWrapper -------------------------------------------------------------------------------- /src/other/BFPRT.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * BFPRT: find the kth element of an array in $ O(n) $ using Divide and Conquer method. 3 | * you can use std::nth_element(a, a + k, a + n) instead 4 | **/ 5 | namespace BFPRT { 6 | template 7 | T kth_index(T* a, int l, int r, int k, Cmp cmp); 8 | 9 | template 10 | int insert_sort(T* a, int l, int r, Cmp cmp) { 11 | for (int i = l + 1; i <= r; ++i) { 12 | int tmp = a[i]; 13 | int j = i - 1; 14 | while (j >= l && a[j] > tmp) { 15 | a[j + 1] = a[j]; 16 | --j; 17 | } 18 | a[j + 1] = tmp; 19 | } 20 | return l + (r - l) / 2; 21 | } 22 | 23 | template 24 | int pivot(T* a, int l, int r, Cmp cmp) { 25 | if (r - l < 5) 26 | return insert_sort(a, l, r, cmp); 27 | int lst = l - 1; 28 | for (int i = l; i + 4 <= r; i += 5) { 29 | int p = insert_sort(a, i, i + 4, cmp); 30 | swap(a[++lst], a[p]); 31 | } 32 | return kth_index(a, l, lst, (lst - l + 1) / 2 + 1, cmp); 33 | } 34 | 35 | template 36 | int partition(T* a, int l, int r, Cmp cmp) { 37 | int p = pivot(a, l, r, cmp); 38 | swap(a[p], a[r]); 39 | int lst = l - 1; 40 | for (int i = l; i < r; ++i) { 41 | if (cmp(a[i], a[r])) 42 | swap(a[++lst], a[i]); 43 | } 44 | swap(a[++lst], a[r]); 45 | return lst; 46 | } 47 | 48 | template 49 | T kth_index(T* a, int l, int r, int k, Cmp cmp) { 50 | int p = partition(a, l, r, cmp); 51 | int d = p - l + 1; 52 | if (d == k) 53 | return p; 54 | else if (d < k) 55 | return kth_index(a, p + 1, r, k - d, cmp); 56 | else 57 | return kth_index(a, l, p - 1, k, cmp); 58 | } 59 | 60 | template 61 | T kth_index(T* a, int l, int r, int k) { 62 | return kth_index(a, l, r, k, less()); 63 | } 64 | }; // namespace BFPRT -------------------------------------------------------------------------------- /src/other/SimulateAnneal.cpp: -------------------------------------------------------------------------------- 1 | struct SimulateAnneal { 2 | constexpr static double p = 0.996; 3 | inline double Rand() { return 1.0 * rand() / RAND_MAX; } 4 | 5 | int n; 6 | vector X, Y, W; 7 | double ax, ay; 8 | 9 | SimulateAnneal(int _n) 10 | : n(_n), X(n), Y(n), W(n) {} 11 | 12 | void input() { 13 | for (int i = 0; i < n; ++i) { 14 | read(X[i], Y[i], W[i]); 15 | } 16 | } 17 | 18 | double cost(double x, double y) { 19 | double res = 0; 20 | for (int i = 0; i < n; ++i) { 21 | double dx = X[i] - x; 22 | double dy = Y[i] - y; 23 | double d = sqrt(dx * dx + dy * dy); 24 | res += d * W[i]; 25 | } 26 | return res; 27 | } 28 | 29 | void init() { 30 | ax = 0; 31 | ay = 0; 32 | for (int i = 0; i < n; ++i) 33 | ax += X[i], ay += Y[i]; 34 | ax /= n; 35 | ay /= n; 36 | } 37 | 38 | void simulate_anneal() { 39 | srand(time(0)); 40 | double T = 1e6, TE = 1e-8; 41 | double cx = ax, cy = ay, cc = cost(cx, cy); 42 | while (T > TE) { 43 | double nx = ax + (2 * Rand() - 1) * T; 44 | double ny = ay + (2 * Rand() - 1) * T; 45 | 46 | double nc = cost(nx, ny); 47 | double d = nc - cc; 48 | 49 | if (d < 0) 50 | cc = nc, ax = cx = nx, ay = cy = ny; 51 | else if (exp(-d / T) > Rand()) { 52 | cx = nx; 53 | cy = ny; 54 | } 55 | 56 | T *= p; 57 | } 58 | } 59 | 60 | void work() { 61 | init(); 62 | // try a try, AC is ok. 63 | simulate_anneal(); 64 | simulate_anneal(); 65 | simulate_anneal(); 66 | simulate_anneal(); 67 | } 68 | }; -------------------------------------------------------------------------------- /src/other/debug.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include "to_string.h" 3 | 4 | template 5 | inline void logd_impl(const char* format, T value) { 6 | std::cerr << format << '=' << serialize(value) << std::endl; 7 | } 8 | 9 | template 10 | inline void logd_impl(const char* format, First f, Rest... r) { 11 | while (*format != ',') 12 | std::cerr << *format++; 13 | std::cerr << '=' << serialize(f) << ","; 14 | logd_impl(format + 1, r...); 15 | } 16 | 17 | #define logd(...) \ 18 | std::cerr << __LINE__ << ": "; \ 19 | logd_impl(#__VA_ARGS__, __VA_ARGS__); 20 | 21 | #if defined(__linux__) 22 | namespace LocalStackLimit { 23 | #include 24 | class StackLimitHelper { 25 | public: 26 | StackLimitHelper(int limit) { 27 | // set min stack size to $limit MB 28 | const rlim_t kStackSize = limit * 1024 * 1024; 29 | struct rlimit rl; 30 | int result; 31 | 32 | result = getrlimit(RLIMIT_STACK, &rl); 33 | if (result == 0) { 34 | if (rl.rlim_cur < kStackSize) { 35 | rl.rlim_cur = kStackSize; 36 | result = setrlimit(RLIMIT_STACK, &rl); 37 | if (result != 0) { 38 | fprintf(stderr, "setrlimit returned result = %d\n", result); 39 | } 40 | } 41 | } 42 | fprintf(stderr, "set min stack size to %lu MB\n", kStackSize / 1024 / 1024); 43 | } 44 | }; 45 | #endif 46 | static StackLimitHelper _(256); 47 | } // namespace LocalStackLimit -------------------------------------------------------------------------------- /src/other/java-header.java: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | import java.util.*; 3 | import java.math.*; 4 | 5 | public class Main { 6 | public static void main(String[] args) { 7 | InputStream inputStream = System.in; 8 | OutputStream outputStream = System.out; 9 | InputReader in = new InputReader(inputStream); 10 | PrintWriter out = new PrintWriter(outputStream); 11 | Task solver = new Task(); 12 | 13 | int T = 1; 14 | // T = in.nextInt(); 15 | for (int i = 1; i <= T; ++i) 16 | solver.solve(i, in, out); 17 | 18 | out.close(); 19 | } 20 | 21 | static class Task { 22 | public void solve(int testNumber, InputReader in, PrintWriter out) { 23 | // write your solution here 24 | out.println("Hello World"); 25 | } 26 | } 27 | 28 | static class InputReader { 29 | public BufferedReader reader; 30 | public StringTokenizer tokenizer; 31 | 32 | public InputReader(InputStream stream) { 33 | reader = new BufferedReader(new InputStreamReader(stream), 32768); 34 | tokenizer = null; 35 | } 36 | 37 | public String next() { 38 | while (tokenizer == null || !tokenizer.hasMoreTokens()) { 39 | try { 40 | tokenizer = new StringTokenizer(reader.readLine()); 41 | } catch (IOException e) { 42 | throw new RuntimeException(e); 43 | } 44 | } 45 | return tokenizer.nextToken(); 46 | } 47 | 48 | public int nextInt() { 49 | return Integer.parseInt(next()); 50 | } 51 | 52 | } 53 | } -------------------------------------------------------------------------------- /src/other/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define CPPIO std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0); 4 | #define freep(p) p ? delete p, p = nullptr, void(1) : void(0) 5 | 6 | #ifdef BACKLIGHT 7 | #include "debug.h" 8 | #else 9 | #define logd(...) ; 10 | #endif 11 | 12 | using i64 = int64_t; 13 | using u64 = uint64_t; 14 | 15 | void solve_case(int Case); 16 | 17 | int main(int argc, char* argv[]) { 18 | CPPIO; 19 | int T = 1; 20 | std::cin >> T; 21 | for (int t = 1; t <= T; ++t) { 22 | solve_case(t); 23 | } 24 | return 0; 25 | } 26 | 27 | void solve_case(int Case) {} 28 | -------------------------------------------------------------------------------- /src/other/to_string.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | std::string serialize(T t); 5 | 6 | namespace my { 7 | 8 | std::string to_string(const std::string& s) { 9 | return '"' + s + '"'; 10 | } 11 | 12 | std::string to_string(__int128_t x) { 13 | if (x == 0) 14 | return "0"; 15 | 16 | std::string s; 17 | bool is_negative = false; 18 | if (x < 0) { 19 | is_negative = true; 20 | x = -x; 21 | } 22 | while (x) { 23 | s.push_back('0' + x % 10); 24 | x /= 10; 25 | } 26 | std::reverse(s.begin(), s.end()); 27 | if (is_negative) 28 | s = "-" + s; 29 | 30 | return s; 31 | } 32 | 33 | template 34 | std::string to_string(const std::pair& p) { 35 | return "(" + serialize(p.first) + "," + serialize(p.second) + ")"; 36 | } 37 | 38 | template 39 | std::string to_string(const std::tuple& p) { 40 | return "(" + serialize(std::get<0>(p)) + ", " + serialize(std::get<1>(p)) + ", " + 41 | serialize(std::get<2>(p)) + ")"; 42 | } 43 | 44 | template 45 | std::string to_string(const std::tuple& p) { 46 | return "(" + serialize(std::get<0>(p)) + ", " + serialize(std::get<1>(p)) + ", " + 47 | serialize(std::get<2>(p)) + serialize(std::get<3>(p)) + ")"; 48 | } 49 | 50 | template 51 | std::string to_string(const std::array& arr) { 52 | std::string res = "["; 53 | for (const A& a : arr) 54 | res += serialize(a) + ","; 55 | res += "]"; 56 | return res; 57 | } 58 | 59 | template 60 | std::string to_string(const std::bitset& v) { 61 | std::string res = ""; 62 | for (size_t i = 0; i < N; i++) 63 | res += static_cast('0' + v[i]); 64 | return res; 65 | } 66 | 67 | template 68 | std::string to_string(const std::vector& V) { 69 | std::string res = "["; 70 | for (const T& v : V) 71 | res += serialize(v) + ","; 72 | res += "]"; 73 | return res; 74 | } 75 | 76 | template 77 | std::string to_string(const std::vector>& V) { 78 | std::string res = "\n[\n"; 79 | for (const std::vector& v : V) 80 | res += " " + to_string(v) + "\n"; 81 | res += "]"; 82 | return res; 83 | } 84 | 85 | template 86 | std::string to_string(const std::vector>>& V) { 87 | std::string res = "\n[\n"; 88 | for (const std::vector>& v : V) 89 | res += " " + to_string(v) + "\n"; 90 | res += "]"; 91 | return res; 92 | } 93 | 94 | template 95 | std::string to_string(const std::set& S) { 96 | std::string res = "{"; 97 | for (const T& s : S) 98 | res += serialize(s) + ","; 99 | res += "}"; 100 | return res; 101 | } 102 | 103 | template 104 | std::string to_string(const std::multiset& S) { 105 | std::string res = "{"; 106 | for (const T& s : S) 107 | res += serialize(s) + ","; 108 | res += "}"; 109 | return res; 110 | } 111 | 112 | template 113 | std::string to_string(const std::map& M) { 114 | std::string res = "{"; 115 | for (const std::pair& m : M) 116 | res += to_string(m) + ","; 117 | res += "}"; 118 | return res; 119 | } 120 | 121 | template 122 | std::string to_string(const std::multimap& M) { 123 | std::string res = "{"; 124 | for (const std::pair& m : M) 125 | res += to_string(m) + ","; 126 | res += "}"; 127 | return res; 128 | } 129 | } // namespace my 130 | 131 | template 132 | struct has_std_to_string : std::false_type {}; 133 | 134 | template 135 | struct has_std_to_string()))> : std::true_type {}; 136 | 137 | template 138 | struct has_my_to_string : std::false_type {}; 139 | 140 | template 141 | struct has_my_to_string()))> : std::true_type {}; 142 | 143 | template 144 | struct has_self_to_string : std::false_type {}; 145 | 146 | template 147 | struct has_self_to_string().to_string())> : std::true_type {}; 148 | 149 | template 150 | std::string serialize(T t) { 151 | if constexpr (has_my_to_string::value) { 152 | return my::to_string(t); 153 | } 154 | if constexpr (has_self_to_string::value) { 155 | return t.to_string(); 156 | } 157 | if constexpr (has_std_to_string::value) { 158 | return std::to_string(t); 159 | } 160 | return "no matched to_string"; 161 | } 162 | -------------------------------------------------------------------------------- /src/string/ACAM.cpp: -------------------------------------------------------------------------------- 1 | // Problem: P5357 【模板】AC 自动机(二次加强版) 2 | // Contest: Luogu 3 | // URL: https://www.luogu.com.cn/problem/P5357 4 | // Memory Limit: 256 MB 5 | // Time Limit: 1000 ms 6 | // 7 | // Powered by CP Editor (https://cpeditor.org) 8 | 9 | #include 10 | 11 | #define CPPIO \ 12 | std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0); 13 | 14 | #ifdef BACKLIGHT 15 | #include "debug.h" 16 | #else 17 | #define logd(...) ; 18 | #define ASSERT(x) ; 19 | #define serialize() std::string("") 20 | #endif 21 | 22 | using i64 = int64_t; 23 | using u64 = uint64_t; 24 | 25 | void Initialize(); 26 | void SolveCase(int Case); 27 | 28 | int main(int argc, char* argv[]) { 29 | CPPIO; 30 | int T = 1; 31 | // std::cin >> T; 32 | for (int t = 1; t <= T; ++t) { 33 | SolveCase(t); 34 | } 35 | return 0; 36 | } 37 | 38 | void Initialize() {} 39 | 40 | template 41 | class AcAutomaton { 42 | public: 43 | struct Node { 44 | public: 45 | Node() : child_({nullptr}), trans_({nullptr}), fail_(nullptr) { 46 | cnt_ = 0; 47 | indeg_ = 0; 48 | } 49 | 50 | ~Node() { 51 | for (int i = 0; i < alpha; ++i) { 52 | if (child_[i]) { 53 | delete child_[i]; 54 | child_[i] = nullptr; 55 | } 56 | } 57 | } 58 | 59 | public: 60 | std::array child_; 61 | std::array trans_; 62 | Node* fail_; 63 | 64 | public: 65 | std::vector ids_; 66 | int cnt_; 67 | int indeg_; 68 | }; 69 | 70 | private: 71 | void traverse(const std::function& f) { 72 | std::queue q; 73 | q.push(root_); 74 | while (!q.empty()) { 75 | Node* p = q.front(); 76 | q.pop(); 77 | 78 | f(p); 79 | 80 | for (int c = 0; c < alpha; ++c) { 81 | if (p->child_[c]) { 82 | q.push(p->child_[c]); 83 | } 84 | } 85 | } 86 | } 87 | 88 | public: 89 | void Insert(const std::vector& s, int id) { 90 | Node* p = root_; 91 | for (int i = 0; i < s.size(); ++i) { 92 | int c = s[i]; 93 | if (p->child_[c] == nullptr) { 94 | p->child_[c] = new Node(); 95 | } 96 | p = p->child_[c]; 97 | } 98 | p->ids_.push_back(id); 99 | } 100 | 101 | void Build() { 102 | std::queue q; 103 | q.push(root_); 104 | 105 | while (!q.empty()) { 106 | Node* p = q.front(); 107 | q.pop(); 108 | 109 | for (int c = 0; c < alpha; ++c) { 110 | if (p->child_[c]) { 111 | p->trans_[c] = p->child_[c]; 112 | 113 | if (p == root_) 114 | p->trans_[c]->fail_ = root_; 115 | else 116 | p->trans_[c]->fail_ = p->fail_->trans_[c]; 117 | 118 | q.push(p->child_[c]); 119 | } else { 120 | if (p == root_) 121 | p->trans_[c] = root_; 122 | else 123 | p->trans_[c] = p->fail_->trans_[c]; 124 | } 125 | } 126 | } 127 | } 128 | 129 | std::vector Query(int n, const std::vector& s) { 130 | std::vector count(n, 0); 131 | 132 | Node* p = root_; 133 | int m = s.size(); 134 | for (int i = 0; i < m; ++i) { 135 | int c = s[i]; 136 | p = p->trans_[c]; 137 | 138 | ++p->cnt_; 139 | } 140 | 141 | traverse([](Node* p) { 142 | if (p->fail_) 143 | ++p->fail_->indeg_; 144 | }); 145 | 146 | std::queue q; 147 | traverse([&q](Node* p) { 148 | if (p->indeg_ == 0) { 149 | q.push(p); 150 | } 151 | }); 152 | 153 | while (!q.empty()) { 154 | Node* p = q.front(); 155 | q.pop(); 156 | 157 | if (!p->ids_.empty()) { 158 | for (int id : p->ids_) 159 | count[id] = p->cnt_; 160 | } 161 | 162 | if (p->fail_) { 163 | --p->fail_->indeg_; 164 | if (p->fail_->indeg_ == 0) 165 | q.push(p->fail_); 166 | 167 | p->fail_->cnt_ += p->cnt_; 168 | } 169 | } 170 | 171 | return count; 172 | } 173 | 174 | public: 175 | AcAutomaton() : root_(new Node()) {} 176 | 177 | ~AcAutomaton() { delete root_; } 178 | 179 | private: 180 | Node* root_; 181 | }; 182 | using AcAM = AcAutomaton<26>; 183 | 184 | void SolveCase(int Case) { 185 | auto ToVec = [](const std::string& s) { 186 | int n = s.size(); 187 | std::vector a(n); 188 | for (int i = 0; i < n; ++i) 189 | a[i] = s[i] - 'a'; 190 | return a; 191 | }; 192 | 193 | int n; 194 | std::cin >> n; 195 | 196 | AcAM ac; 197 | std::string s; 198 | for (int i = 0; i < n; ++i) { 199 | std::cin >> s; 200 | ac.Insert(ToVec(s), i); 201 | } 202 | ac.Build(); 203 | 204 | std::cin >> s; 205 | std::vector count = ac.Query(n, ToVec(s)); 206 | 207 | for (int i = 0; i < n; ++i) 208 | std::cout << count[i] << "\n"; 209 | } 210 | -------------------------------------------------------------------------------- /src/string/GSAM.cpp: -------------------------------------------------------------------------------- 1 | namespace GSAM { 2 | using T = char; 3 | 4 | inline int idx(T c) { 5 | return c - 'a'; 6 | } 7 | 8 | const int __N = N << 1; 9 | const int __M = 26; 10 | 11 | int tot, next[__N][__M]; 12 | int len[__N], fail[__N]; 13 | 14 | inline void init() { 15 | tot = 0; 16 | fail[0] = -1; 17 | len[0] = 0; 18 | memset(next[0], 0, sizeof(next[0])); 19 | } 20 | 21 | inline int newnode() { 22 | ++tot; 23 | fail[tot] = 0; 24 | len[tot] = 0; 25 | memset(next[tot], 0, sizeof(next[tot])); 26 | return tot; 27 | } 28 | 29 | void insertTrie(const T* s, int n) { 30 | int p = 0, c; 31 | for (int i = 0; i < n; ++i) { 32 | c = idx(s[i]); 33 | if (!next[p][c]) 34 | next[p][c] = newnode(); 35 | p = next[p][c]; 36 | } 37 | } 38 | 39 | int extendSAM(int last, int c) { 40 | int cur = next[last][c]; 41 | if (len[cur]) 42 | return cur; 43 | len[cur] = len[last] + 1; 44 | 45 | int p = fail[last]; 46 | while (p != -1) { 47 | if (!next[p][c]) 48 | next[p][c] = cur; 49 | else 50 | break; 51 | p = fail[p]; 52 | } 53 | 54 | if (p == -1) { 55 | fail[cur] = 0; 56 | return cur; 57 | } 58 | 59 | int q = next[p][c]; 60 | if (len[p] + 1 == len[q]) { 61 | fail[cur] = q; 62 | return cur; 63 | } 64 | 65 | int clone = newnode(); 66 | for (int i = 0; i < __M; ++i) 67 | next[clone][i] = len[next[q][i]] ? next[q][i] : 0; 68 | 69 | len[clone] = len[p] + 1; 70 | while (p != -1 && next[p][c] == q) { 71 | next[p][c] = clone; 72 | p = fail[p]; 73 | } 74 | fail[clone] = fail[q]; 75 | fail[cur] = clone; 76 | fail[q] = clone; 77 | return cur; 78 | } 79 | 80 | void build() { 81 | queue> q; 82 | for (int i = 0; i < __M; ++i) 83 | if (next[0][i]) 84 | q.push(make_pair(0, i)); 85 | 86 | while (!q.empty()) { 87 | pair u = q.front(); 88 | q.pop(); 89 | int last = extendSAM(u.first, u.second); 90 | for (int i = 0; i < __M; ++i) 91 | if (next[last][i]) 92 | q.push(make_pair(last, i)); 93 | } 94 | } 95 | 96 | // 多模式串--本质不同子串数 97 | ll count() { 98 | ll res = 0; 99 | for (int i = 1; i <= tot; ++i) 100 | res += len[i] - len[fail[i]]; 101 | return res; 102 | } 103 | } // namespace GSAM -------------------------------------------------------------------------------- /src/string/KMP.cpp: -------------------------------------------------------------------------------- 1 | namespace String { 2 | 3 | template 4 | std::vector KMP(const String& s) { 5 | int n = s.size(); 6 | std::vector p(n); 7 | p[0] = 0; 8 | for (int i = 1, j = 0; i < n; ++i) { 9 | while (j > 0 && s[i] != s[j]) 10 | j = p[j - 1]; 11 | if (s[i] == s[j]) 12 | ++j; 13 | p[i] = j; 14 | } 15 | return p; 16 | } 17 | 18 | template 19 | std::vector Match(const String& s, const String& t) { 20 | int n = s.size(); 21 | auto p = KMP(s); 22 | 23 | int m = t.size(); 24 | std::vector r; 25 | for (int i = 0, j = 0; i < m; ++i) { 26 | while (j == n || (j > 0 && t[i] != s[j])) 27 | j = p[j - 1]; 28 | if (s[j] == t[i]) 29 | ++j; 30 | 31 | if (j == n) { 32 | r.push_back(i - n + 1); 33 | } 34 | } 35 | 36 | return r; 37 | } 38 | 39 | } // namespace String -------------------------------------------------------------------------------- /src/string/Manacher.cpp: -------------------------------------------------------------------------------- 1 | namespace Manacher { 2 | // 1-based 3 | 4 | const int __N = N << 1; 5 | 6 | char s[__N]; 7 | int n, len[__N]; 8 | 9 | // @ t1 t2 t3 \0 10 | // ==> @ # t1 # t2 # t3 # \0 11 | inline void init(char* t, int m) { 12 | n = 2 * m + 1; 13 | s[0] = '@'; 14 | s[n] = '#'; 15 | s[n + 1] = 0; 16 | for (int i = 1; i <= m; ++i) { 17 | s[2 * i - 1] = '#'; 18 | s[2 * i] = t[i]; 19 | } 20 | } 21 | 22 | // s[i-len[i]...i+len[i]] is palindromic 23 | // len[i]-1 is palindromic length in t 24 | void manacher(char* t, int m) { 25 | init(t, m); 26 | for (int i = 1, l = 0, r = 0, k; i <= n; ++i) { 27 | k = i > r ? 1 : min(r - i, len[l + r - i]); 28 | while (s[i - k] == s[i + k]) 29 | ++k; 30 | len[i] = k--; 31 | if (i + k > r) { 32 | l = i - k; 33 | r = i + k; 34 | } 35 | } 36 | } 37 | 38 | int getMaxPalindromicLength(char* t, int m) { 39 | manacher(t, m); 40 | int ma = 0; 41 | for (int i = 1; i <= n; ++i) 42 | updMax(ma, len[i]); 43 | return ma - 1; 44 | } 45 | } // namespace Manacher -------------------------------------------------------------------------------- /src/string/PAM.cpp: -------------------------------------------------------------------------------- 1 | //最长双倍回文串长度 2 | #include 3 | using namespace std; 4 | 5 | typedef long long ll; 6 | const int N = 5e5 + 5; 7 | 8 | struct Palindromic_Automaton { 9 | //0偶根 1奇根 range[2-tot] 10 | int s[N << 1], now; 11 | int next[N << 1][26], fail[N << 1], len[N << 1], last, tot; 12 | int cnt[N << 1]; //状态i表示的回文串数目 13 | 14 | // extend 15 | int trans[N << 1]; 16 | 17 | void init() { 18 | s[0] = len[1] = -1; 19 | fail[0] = tot = now = 1; 20 | last = len[0] = 0; 21 | memset(next[0], 0, sizeof(next[0])); 22 | memset(next[1], 0, sizeof(next[1])); 23 | } 24 | int newnode() { 25 | tot++; 26 | memset(next[tot], 0, sizeof(next[tot])); 27 | fail[tot] = cnt[tot] = len[tot] = 0; 28 | return tot; 29 | } 30 | int getfail(int x) { 31 | while (s[now - len[x] - 2] != s[now - 1]) 32 | x = fail[x]; 33 | return x; 34 | } 35 | void extend(int c) { 36 | s[now++] = c; 37 | int cur = getfail(last); 38 | if (!next[cur][c]) { 39 | int p = newnode(); 40 | len[p] = len[cur] + 2; 41 | fail[p] = next[getfail(fail[cur])][c]; 42 | next[cur][c] = p; 43 | 44 | // extend 45 | if (len[p] <= 2) 46 | trans[p] = fail[p]; 47 | else { 48 | int tmp = trans[cur]; 49 | while (s[now - len[tmp] - 2] != s[now - 1] || (len[tmp] + 2) * 2 > len[p]) 50 | tmp = fail[tmp]; 51 | trans[p] = next[tmp][c]; 52 | } 53 | } 54 | last = next[cur][c]; 55 | cnt[last]++; 56 | } 57 | int count() { return tot - 1; } 58 | void calc() { 59 | for (int i = tot; i >= 2; --i) 60 | cnt[fail[i]] += cnt[i]; 61 | cnt[0] = cnt[1] = 0; 62 | } 63 | int getans() { 64 | int ans = 0; 65 | for (int i = 2; i <= tot; i++) { 66 | if (len[i] > ans && len[trans[i]] * 2 == len[i] && len[trans[i]] % 2 == 0) 67 | ans = len[i]; 68 | } 69 | return ans; 70 | } 71 | } pam; 72 | 73 | char t[N]; 74 | 75 | int main() { 76 | int n; 77 | scanf("%d", &n); 78 | scanf("%s", t); 79 | pam.init(); 80 | for (int i = 0; i < n; ++i) { 81 | pam.extend(t[i] - 'a'); 82 | } 83 | printf("%d\n", pam.getans()); 84 | return 0; 85 | } -------------------------------------------------------------------------------- /src/string/SAIS.cpp: -------------------------------------------------------------------------------- 1 | namespace SAIS { 2 | // 1 based, O(n) 3 | int s[N << 1], t[N << 1], height[N], sa[N], rk[N], p[N], c[N], w[N]; 4 | inline int trans(int n, int* S) { 5 | int m = *max_element(S + 1, S + 1 + n); 6 | for (int i = 1; i <= n; ++i) 7 | rk[S[i]] = 1; 8 | for (int i = 1; i <= m; ++i) 9 | rk[i] += rk[i - 1]; 10 | for (int i = 1; i <= n; ++i) 11 | s[i] = rk[S[i]]; 12 | return rk[m]; 13 | } 14 | #define ps(x) sa[w[s[x]]--] = x 15 | #define pl(x) sa[w[s[x]]++] = x 16 | inline void radix(int* v, int* s, int* t, int n, int m, int n1) { 17 | memset(sa, 0, n + 1 << 2); 18 | memset(c, 0, m + 1 << 2); 19 | for (int i = 1; i <= n; ++i) 20 | ++c[s[i]]; 21 | for (int i = 1; i <= m; ++i) 22 | w[i] = c[i] += c[i - 1]; 23 | for (int i = n1; i; --i) 24 | ps(v[i]); 25 | for (int i = 1; i <= m; ++i) 26 | w[i] = c[i - 1] + 1; 27 | for (int i = 1; i <= n; ++i) 28 | if (sa[i] > 1 && t[sa[i] - 1]) 29 | pl(sa[i] - 1); 30 | for (int i = 1; i <= m; ++i) 31 | w[i] = c[i]; 32 | for (int i = n; i; --i) 33 | if (sa[i] > 1 && !t[sa[i] - 1]) 34 | ps(sa[i] - 1); 35 | } 36 | inline void SAIS(int n, int m, int* s, int* t, int* p) { 37 | int n1 = 0, ch = rk[1] = 0, *s1 = s + n; 38 | t[n] = 0; 39 | for (int i = n - 1; i; --i) 40 | t[i] = s[i] == s[i + 1] ? t[i + 1] : s[i] > s[i + 1]; 41 | for (int i = 2; i <= n; ++i) 42 | rk[i] = t[i - 1] && !t[i] ? (p[++n1] = i, n1) : 0; 43 | radix(p, s, t, n, m, n1); 44 | for (int i = 1, x, y; i <= n; ++i) 45 | if (x = rk[sa[i]]) { 46 | if (ch <= 1 || p[x + 1] - p[x] != p[y + 1] - p[y]) 47 | ++ch; 48 | else 49 | for (int j = p[x], k = p[y]; j <= p[x + 1]; ++j, ++k) 50 | if ((s[j] << 1 | t[j]) ^ (s[k] << 1 | t[k])) { 51 | ++ch; 52 | break; 53 | } 54 | s1[y = x] = ch; 55 | } 56 | if (ch < n1) 57 | SAIS(n1, ch, s1, t + n, p + n1); 58 | else 59 | for (int i = 1; i <= n1; ++i) 60 | sa[s1[i]] = i; 61 | for (int i = 1; i <= n1; ++i) 62 | s1[i] = p[sa[i]]; 63 | radix(s1, s, t, n, m, n1); 64 | } 65 | inline void build_sa(int* S, int n) { 66 | int m = trans(++n, S); 67 | SAIS(n, m, s, t, p); 68 | for (int i = 1; i < n; ++i) 69 | rk[sa[i] = sa[i + 1]] = i; 70 | for (int i = 1, j, k = 0; i < n; ++i) 71 | if (rk[i] > 1) { 72 | for (j = sa[rk[i] - 1]; S[i + k] == S[j + k]; ++k) 73 | ; 74 | if (height[rk[i]] = k) 75 | --k; 76 | } 77 | } 78 | } // namespace SAIS -------------------------------------------------------------------------------- /src/string/SAM.cpp: -------------------------------------------------------------------------------- 1 | //广义后缀自动机:insert后重新将last赋1 (复杂度好像有可能退化) 2 | #include 3 | using namespace std; 4 | 5 | typedef long long ll; 6 | const int maxn = 1e6 + 5; 7 | 8 | char s[maxn]; 9 | struct Suffix_Automaton { 10 | //初始状态为0,range[0...tot-1] 11 | struct state { 12 | int len, link; 13 | map next; 14 | } st[maxn << 1]; 15 | int last, tot; 16 | 17 | void init() { 18 | st[0].len = 0; 19 | st[0].link = -1; 20 | tot++; 21 | last = 0; 22 | } 23 | 24 | void extend(char c) { 25 | int cur = tot++; 26 | st[cur].len = st[last].len + 1; 27 | int p = last; 28 | while (p != -1 && !st[p].next.count(c)) { 29 | st[p].next[c] = cur; 30 | p = st[p].link; 31 | } 32 | if (p == -1) 33 | st[cur].link = 0; 34 | else { 35 | int q = st[p].next[c]; 36 | if (st[p].len + 1 == st[q].len) 37 | st[cur].link = q; 38 | else { 39 | int clone = tot++; 40 | st[clone].len = st[p].len + 1; 41 | st[clone].next = st[q].next; 42 | st[clone].link = st[q].link; 43 | while (p != -1 && st[p].next[c] == q) { 44 | st[p].next[c] = clone; 45 | p = st[p].link; 46 | } 47 | st[q].link = st[cur].link = clone; 48 | } 49 | } 50 | last = cur; 51 | } 52 | 53 | ll count() { 54 | ll res = 0; 55 | for (int i = 0; i < tot; i++) 56 | res += st[i].len - st[st[i].link].len; 57 | return res; 58 | } 59 | } sam; 60 | 61 | int main() { 62 | scanf("%s", s); 63 | sam.init(); 64 | for (int i = 0; s[i] != 0; i++) 65 | sam.extend(s[i]); 66 | printf("%lld\n", sam.count()); 67 | return 0; 68 | } -------------------------------------------------------------------------------- /src/string/SqAM.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * 识别一个串的子序列, O(n^2) 3 | * 用法类似后缀自动机 4 | */ 5 | struct SqAM { 6 | int next[N << 1][26], pre[N << 1], lst[26]; 7 | int root, tot; 8 | void init() { 9 | root = tot = 1; 10 | for (int i = 0; i < 26; i++) 11 | lst[i] = 1; 12 | } 13 | 14 | void extend(int c) { 15 | int p = lst[c], np = ++tot; 16 | pre[np] = p; 17 | for (int i = 0; i < 26; i++) 18 | for (int j = lst[i]; j && !next[j][c]; j = pre[j]) 19 | next[j][c] = np; 20 | lst[c] = np; 21 | } 22 | }; -------------------------------------------------------------------------------- /src/string/StringHash.cpp: -------------------------------------------------------------------------------- 1 | namespace String { 2 | 3 | template 4 | class SingleStringHash { 5 | private: 6 | static std::vector b_; 7 | 8 | void TryExtendBase(int n) { 9 | while ((int)b_.size() < n + 1) { 10 | int x = b_.back(); 11 | b_.push_back(int64_t(1) * x * p % m); 12 | } 13 | } 14 | 15 | public: 16 | SingleStringHash(const std::string& s) : n_(s.size()), h_(n_ + 1) { 17 | TryExtendBase(n_); 18 | 19 | h_[0] = 0; 20 | for (int i = 0; i < n_; ++i) 21 | h_[i + 1] = (int64_t(1) * h_[i] * p % m + s[i]) % m; 22 | } 23 | 24 | int Get(int l, int r) const { 25 | ASSERT(0 <= l && l <= r && r < n_); 26 | ++l, ++r; 27 | int hash = (h_[r] - int64_t(1) * h_[l - 1] * b_[r - l + 1] % m + m) % m; 28 | return hash; 29 | } 30 | 31 | public: 32 | int n_; 33 | std::vector h_; 34 | }; 35 | template 36 | std::vector SingleStringHash::b_ = {1}; 37 | 38 | template 39 | class DoubleStringHash { 40 | public: 41 | DoubleStringHash(const std::string& s) 42 | : n_(s.size()), hash_lo_(s), hash_hi_(s) {} 43 | 44 | int64_t Get(int l, int r) const { 45 | ASSERT(0 <= l && l <= r && r < n_); 46 | int lo = hash_lo_.Get(l, r); 47 | int hi = hash_hi_.Get(l, r); 48 | return int64_t(1) * hi * m_lo + lo; 49 | } 50 | 51 | public: 52 | int n_; 53 | SingleStringHash hash_lo_; 54 | SingleStringHash hash_hi_; 55 | }; 56 | 57 | } // namespace String 58 | using StringHash = String::DoubleStringHash<29, 998'244'353, 31, 1'000'000'007>; -------------------------------------------------------------------------------- /src/string/SuffixBST.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * 1. 在当前字符串的后面插入字符 3 | * 2. 在当前字符串的后面删除字符 4 | * 3. 询问字符串t作为连续子串在当前字符串中出现了几次 5 | * */ 6 | #include 7 | using namespace std; 8 | 9 | const int N = 8e5 + 5; 10 | const double INF = 1e18; 11 | 12 | void decode(char* s, int len, int mask) { 13 | for (int i = 0; i < len; ++i) { 14 | mask = (mask * 131 + i) % len; 15 | swap(s[i], s[mask]); 16 | } 17 | } 18 | 19 | int q, n, na; 20 | char a[N], t[N]; 21 | 22 | // SuffixBST(SGT Ver) 23 | 24 | // 顺序加入,查询时将询问串翻转 25 | // 以i结束的前缀,对应节点的编号为i 26 | // 注意:不能写懒惰删除,否则可能会破坏树的结构 27 | const double alpha = 0.75; 28 | int root; 29 | int sz[N], L[N], R[N]; 30 | double tag[N]; 31 | int buffer_size, buffer[N]; 32 | 33 | bool cmp(int x, int y) { 34 | if (t[x] != t[y]) 35 | return t[x] < t[y]; 36 | return tag[x - 1] < tag[y - 1]; 37 | } 38 | 39 | void init() { 40 | root = 0; 41 | } 42 | 43 | void new_node(int& rt, int p, double lv, double rv) { 44 | rt = p; 45 | sz[rt] = 1; 46 | tag[rt] = (lv + rv) / 2; 47 | L[rt] = R[rt] = 0; 48 | } 49 | 50 | void push_up(int x) { 51 | if (!x) 52 | return; 53 | sz[x] = sz[L[x]] + 1 + sz[R[x]]; 54 | } 55 | 56 | bool balance(int rt) { 57 | return alpha * sz[rt] > max(sz[L[rt]], sz[R[rt]]); 58 | } 59 | 60 | void flatten(int rt) { 61 | if (!rt) 62 | return; 63 | flatten(L[rt]); 64 | buffer[++buffer_size] = rt; 65 | flatten(R[rt]); 66 | } 67 | 68 | void build(int& rt, int l, int r, double lv, double rv) { 69 | if (l > r) { 70 | rt = 0; 71 | return; 72 | } 73 | int mid = (l + r) >> 1; 74 | double mv = (lv + rv) / 2; 75 | 76 | rt = buffer[mid]; 77 | tag[rt] = mv; 78 | build(L[rt], l, mid - 1, lv, mv); 79 | build(R[rt], mid + 1, r, mv, rv); 80 | push_up(rt); 81 | } 82 | 83 | void rebuild(int& rt, double lv, double rv) { 84 | buffer_size = 0; 85 | flatten(rt); 86 | build(rt, 1, buffer_size, lv, rv); 87 | } 88 | 89 | void insert(int& rt, int p, double lv, double rv) { 90 | if (!rt) { 91 | new_node(rt, p, lv, rv); 92 | return; 93 | } 94 | 95 | if (cmp(p, rt)) 96 | insert(L[rt], p, lv, tag[rt]); 97 | else 98 | insert(R[rt], p, tag[rt], rv); 99 | 100 | push_up(rt); 101 | if (!balance(rt)) 102 | rebuild(rt, lv, rv); 103 | } 104 | 105 | void remove(int& rt, int p, double lv, double rv) { 106 | if (!rt) 107 | return; 108 | 109 | if (rt == p) { 110 | if (!L[rt] || !R[rt]) { 111 | rt = (L[rt] | R[rt]); 112 | } else { 113 | // 找到rt的前驱来替换rt 114 | int nrt = L[rt], fa = rt; 115 | while (R[nrt]) { 116 | fa = nrt; 117 | sz[fa]--; 118 | nrt = R[nrt]; 119 | } 120 | if (fa == rt) { 121 | R[nrt] = R[rt]; 122 | } else { 123 | L[nrt] = L[rt]; 124 | R[nrt] = R[rt]; 125 | R[fa] = 0; 126 | } 127 | rt = nrt; 128 | tag[rt] = (lv + rv) / 2; 129 | } 130 | } else { 131 | double mv = (lv + rv) / 2; 132 | if (cmp(p, rt)) 133 | remove(L[rt], p, lv, mv); 134 | else 135 | remove(R[rt], p, mv, rv); 136 | } 137 | 138 | push_up(rt); 139 | if (!balance(rt)) 140 | rebuild(rt, lv, rv); 141 | } 142 | 143 | bool cmp1(char* s, int len, int p) { 144 | for (int i = 1; i <= len; ++i, --p) { 145 | if (s[i] < t[p]) 146 | return true; 147 | if (s[i] > t[p]) 148 | return false; 149 | } 150 | } 151 | 152 | int query(int rt, char* s, int len) { 153 | if (!rt) 154 | return 0; 155 | if (cmp1(s, len, rt)) 156 | return query(L[rt], s, len); 157 | else 158 | return sz[L[rt]] + 1 + query(R[rt], s, len); 159 | } 160 | 161 | void solve(int Case) { 162 | n = 0; 163 | scanf("%d", &q); 164 | init(); 165 | 166 | scanf("%s", a + 1); 167 | na = strlen(a + 1); 168 | for (int i = 1; i <= na; ++i) { 169 | t[++n] = a[i]; 170 | insert(root, n, 0, INF); 171 | } 172 | 173 | int mask = 0; 174 | char op[10]; 175 | for (int i = 1; i <= q; ++i) { 176 | scanf("%s", op); 177 | if (op[0] == 'A') { 178 | scanf("%s", a + 1); 179 | na = strlen(a + 1); 180 | decode(a + 1, na, mask); 181 | 182 | for (int i = 1; i <= na; ++i) { 183 | t[++n] = a[i]; 184 | insert(root, n, 0, INF); 185 | } 186 | } else if (op[0] == 'D') { 187 | int x; 188 | scanf("%d", &x); 189 | while (x) { 190 | remove(root, n, 0, INF); 191 | --n; 192 | --x; 193 | } 194 | } else if (op[0] == 'Q') { 195 | scanf("%s", a + 1); 196 | na = strlen(a + 1); 197 | decode(a + 1, na, mask); 198 | 199 | reverse(a + 1, a + 1 + na); 200 | 201 | a[na + 1] = 'Z' + 1; 202 | a[na + 2] = 0; 203 | int ans = query(root, a, na + 1); 204 | 205 | --a[na]; 206 | ans -= query(root, a, na + 1); 207 | 208 | printf("%d\n", ans); 209 | mask ^= ans; 210 | } 211 | } 212 | } 213 | 214 | int main() { 215 | int T = 1; 216 | for (int i = 1; i <= T; ++i) 217 | solve(i); 218 | return 0; 219 | } -------------------------------------------------------------------------------- /src/string/SufixArray.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Build Suffix Array in O(n \log n) with binary lifting and radix sort. 3 | * 4 | * Idea 5 | * 6 | * Assume that the rank of all substrings with lenght w is known, let call it 7 | * rank_{w}, then let rank_w(i) be the first key, and rank_w(i + w) be the 8 | * second key. rank_{2w} can be calculated by using radix sort. 9 | * 10 | * Reference 11 | * 12 | * https://oi-wiki.org/string/sa/ 13 | */ 14 | template 15 | std::tuple, std::vector, std::vector> SuffixArray( 16 | const String& s) { 17 | int n = s.size(), m = alpha; 18 | 19 | /** 20 | * suffix(i) means s_i...s_{n-1} 21 | * sa[i] is start position fo the i-th smallest prefix 22 | * rank[i] is rank of the suffix(i) 23 | * lcp[i] means longest common prefix between suffix(sa[i]) and suffix(sa[i - 24 | * 1]) 25 | */ 26 | std::vector sa(n), rank(n), lcp(n); 27 | std::vector count(std::max(m, n), 0), old_rank(n), temp(n); 28 | 29 | // build sa with binary lifting and raidx sort. 30 | for (int i = 0; i < n; ++i) { 31 | rank[i] = s[i]; 32 | ++count[rank[i]]; 33 | } 34 | for (int i = 1; i < m; ++i) { 35 | count[i] += count[i - 1]; 36 | } 37 | for (int i = n - 1; i >= 0; --i) { 38 | sa[--count[rank[i]]] = i; 39 | } 40 | 41 | for (int length = 1; length < n; length = length * 2) { 42 | // second key. 43 | int p = 0; 44 | for (int i = n - length; i < n; ++i) 45 | temp[p++] = i; 46 | for (int i = 0; i < n; ++i) 47 | if (sa[i] >= length) 48 | temp[p++] = sa[i] - length; 49 | 50 | // first key. 51 | std::fill(count.begin(), count.end(), 0); 52 | for (int i = 0; i < n; ++i) 53 | ++count[rank[temp[i]]]; 54 | for (int i = 1; i < m; ++i) 55 | count[i] += count[i - 1]; 56 | for (int i = n - 1; i >= 0; --i) { 57 | sa[--count[rank[temp[i]]]] = temp[i]; 58 | } 59 | 60 | old_rank = rank; 61 | m = 0; 62 | rank[sa[0]] = m++; 63 | for (int i = 1; i < n; ++i) { 64 | if (old_rank[sa[i]] == old_rank[sa[i - 1]] && 65 | ((sa[i] + length < n ? old_rank[sa[i] + length] : -1) == 66 | (sa[i - 1] + length < n ? old_rank[sa[i - 1] + length] : -1))) { 67 | rank[sa[i]] = m - 1; 68 | } else { 69 | rank[sa[i]] = m++; 70 | } 71 | } 72 | 73 | if (m == n) 74 | break; 75 | } 76 | 77 | // longest common prefix 78 | for (int i = 0, k = 0; i < n; ++i) { 79 | if (rank[i] == 0) 80 | continue; 81 | if (k) 82 | --k; 83 | while (i + k < n && sa[rank[i] - 1] + k < n && 84 | s[i + k] == s[sa[rank[i] - 1] + k]) 85 | ++k; 86 | lcp[rank[i]] = k; 87 | } 88 | 89 | return {sa, rank, lcp}; 90 | } -------------------------------------------------------------------------------- /src/string/Trie.cpp: -------------------------------------------------------------------------------- 1 | // Problem: P8306 【模板】字典树 2 | // Contest: Luogu 3 | // URL: https://www.luogu.com.cn/problem/P8306 4 | // Memory Limit: 1024 MB 5 | // Time Limit: 1000 ms 6 | // 7 | // Powered by CP Editor (https://cpeditor.org) 8 | 9 | #include 10 | 11 | #define CPPIO \ 12 | std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0); 13 | 14 | #ifdef BACKLIGHT 15 | #include "debug.h" 16 | #else 17 | #define logd(...) ; 18 | #define ASSERT(x) ; 19 | #define serialize() std::string("") 20 | #endif 21 | 22 | using i64 = int64_t; 23 | using u64 = uint64_t; 24 | 25 | void Initialize(); 26 | void SolveCase(int Case); 27 | 28 | int main(int argc, char* argv[]) { 29 | CPPIO; 30 | int T = 1; 31 | std::cin >> T; 32 | for (int t = 1; t <= T; ++t) { 33 | SolveCase(t); 34 | } 35 | return 0; 36 | } 37 | 38 | void Initialize() {} 39 | 40 | template 41 | class Trie { 42 | public: 43 | struct Node { 44 | public: 45 | Node() : child_({nullptr}) { pass_ = 0; } 46 | 47 | ~Node() { 48 | for (int i = 0; i < alpha; ++i) { 49 | if (child_[i]) { 50 | delete child_[i]; 51 | child_[i] = nullptr; 52 | } 53 | } 54 | } 55 | 56 | public: 57 | std::array child_; 58 | 59 | public: 60 | int pass_; 61 | }; 62 | 63 | public: 64 | void Insert(const std::vector& s) { 65 | Node* p = root_; 66 | for (int i = 0; i < s.size(); ++i) { 67 | int c = s[i]; 68 | if (p->child_[c] == nullptr) { 69 | p->child_[c] = new Node(); 70 | } 71 | p = p->child_[c]; 72 | 73 | ++p->pass_; 74 | } 75 | } 76 | 77 | int Query(const std::vector& s) { 78 | Node* p = root_; 79 | int n = s.size(); 80 | for (int i = 0; i < n; ++i) { 81 | int c = s[i]; 82 | 83 | if (p->child_[c] == nullptr) 84 | return 0; 85 | 86 | p = p->child_[c]; 87 | } 88 | 89 | return p->pass_; 90 | } 91 | 92 | public: 93 | Trie() : root_(new Node()) {} 94 | 95 | ~Trie() { delete root_; } 96 | 97 | private: 98 | Node* root_; 99 | }; 100 | 101 | std::vector ToVec(const std::string& s) { 102 | int n = s.size(); 103 | std::vector a(n); 104 | for (int i = 0; i < n; ++i) { 105 | int c; 106 | if (isdigit(s[i])) 107 | c = s[i] - '0'; 108 | else if (islower(s[i])) 109 | c = 10 + s[i] - 'a'; 110 | else 111 | c = 36 + s[i] - 'A'; 112 | a[i] = c; 113 | } 114 | return a; 115 | } 116 | 117 | void SolveCase(int Case) { 118 | int n, q; 119 | std::cin >> n >> q; 120 | 121 | Trie<62> trie; 122 | std::string s; 123 | for (int i = 0; i < n; ++i) { 124 | std::cin >> s; 125 | trie.Insert(ToVec(s)); 126 | } 127 | 128 | for (int i = 0; i < q; ++i) { 129 | std::cin >> s; 130 | std::cout << trie.Query(ToVec(s)) << "\n"; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/string/ZAlgorithm.cpp: -------------------------------------------------------------------------------- 1 | namespace ZAlgorithm { 2 | // 1-based 3 | 4 | // z_i = LCP(s, s[i..n]) 5 | void getZ(char* s, int n, int* z) { 6 | z[1] = n; 7 | for (int i = 2, l = 0, r = 0; i <= n; ++i) { 8 | if (i <= r) 9 | z[i] = min(r - i + 1, z[i - l + 1]); 10 | else 11 | z[i] = 0; 12 | while (i + z[i] <= n && s[z[i] + 1] == s[i + z[i]]) 13 | ++z[i]; 14 | if (i + z[i] - 1 > r) 15 | l = i, r = i + z[i] - 1; 16 | } 17 | } 18 | 19 | // p_i = LCP(s, t[i...m]) 20 | void EXKMP(char* s, int n, int* z, char* t, int m, int* p) { 21 | getZ(s, n, z); 22 | for (int i = 1, l = 0, r = 0; i <= m; ++i) { 23 | if (i <= r) 24 | p[i] = min(r - i + 1, z[i - l + 1]); 25 | else 26 | p[i] = 0; 27 | while (i + p[i] <= m && s[p[i] + 1] == t[i + p[i]]) 28 | ++p[i]; 29 | if (i + p[i] - 1 > r) 30 | l = i, r = i + p[i] - 1; 31 | } 32 | } 33 | } // namespace ZAlgorithm -------------------------------------------------------------------------------- /template.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Backl1ght/competitive-programming-code-template/6c1080733d384e3373705d94f0f2fbfa163cfc38/template.pdf -------------------------------------------------------------------------------- /tex/config.yml: -------------------------------------------------------------------------------- 1 | content: 2 | ds: 3 | - AVLTree: src/ds/AVLTree.cpp 4 | - BTree: src/ds/BTree.cpp 5 | - CaptainMo: src/ds/CaptainMo.cpp 6 | - CDQ: src/ds/CDQ.cpp 7 | - FenwickTree: src/ds/FenwickTree.cpp 8 | - KDTree: src/ds/KDTree.cpp 9 | - LCT: src/ds/LCT.cpp 10 | - LefitstTree: src/ds/LefitstTree.cpp 11 | - PersistentSegmentTree: src/ds/PersistentSegmentTree.cpp 12 | - rbtree-1: src/ds/rbtree-1.cpp 13 | - RBTree: src/ds/RBTree.cpp 14 | - RMQ: src/ds/RMQ.cpp 15 | - RollBackCaptainMo: src/ds/RollBackCaptainMo.cpp 16 | - SegmentTree: src/ds/SegmentTree.cpp 17 | - SGTree: src/ds/SGTree.cpp 18 | - Splay: src/ds/Splay.cpp 19 | - Treap-pointer: src/ds/Treap-pointer.cpp 20 | - Treap: src/ds/Treap.cpp 21 | graph: 22 | - BCC-Edge: src/graph/BCC-Edge.cpp 23 | - BCC-Point: src/graph/BCC-Point.cpp 24 | - BiGraphMatch: src/graph/BiGraphMatch.cpp 25 | - BiWraphMatch: src/graph/BiWraphMatch.cpp 26 | - BlockForest: src/graph/BlockForest.cpp 27 | - BlockTree: src/graph/BlockTree.cpp 28 | - Dijkstra: src/graph/Dijkstra.cpp 29 | - dsu-on-tree: src/graph/dsu-on-tree.cpp 30 | - ExKruskal: src/graph/ExKruskal.cpp 31 | - FullyDCP: src/graph/FullyDCP.cpp 32 | - Graph: src/graph/Graph.cpp 33 | - GraphMatch: src/graph/GraphMatch.cpp 34 | - HLD-Edge: src/graph/HLD-Edge.cpp 35 | - Kosaraju: src/graph/Kosaraju.cpp 36 | - Kruskal: src/graph/Kruskal.cpp 37 | - LCA-HLD: src/graph/LCA-HLD.cpp 38 | - LCA: src/graph/LCA.cpp 39 | - maxflow: src/graph/maxflow.cpp 40 | - mincostflow: src/graph/mincostflow.cpp 41 | - SCC: src/graph/SCC.cpp 42 | - SPFA: src/graph/SPFA.cpp 43 | - tree-divide: src/graph/tree-divide.cpp 44 | - Wraph: src/graph/Wraph.cpp 45 | - WraphMatch: src/graph/WraphMatch.cpp 46 | math: 47 | - 2DGeometry: src/math/2DGeometry.cpp 48 | - 3DGeometry: src/math/3DGeometry.cpp 49 | - BigInt: src/math/BigInt.cpp 50 | - BSGS: src/math/BSGS.cpp 51 | - Cipolla: src/math/Cipolla.cpp 52 | - Combination: src/math/Combination.cpp 53 | - CRT: src/math/CRT.cpp 54 | - du: src/math/du.cpp 55 | - EulerSeive: src/math/EulerSeive.cpp 56 | - eval: src/math/eval.cpp 57 | - EXGCD: src/math/EXGCD.cpp 58 | - FFT: src/math/FFT.cpp 59 | - FWT: src/math/FWT.cpp 60 | - LinearBasis: src/math/LinearBasis.cpp 61 | - Lucas: src/math/Lucas.cpp 62 | - min25: src/math/min25.cpp 63 | - Mint: src/math/Mint.cpp 64 | - Mobius: src/math/Mobius.cpp 65 | - Modular: src/math/Modular.cpp 66 | - NTT: src/math/NTT.cpp 67 | - PollardRho: src/math/PollardRho.cpp 68 | - poly-struct: src/math/poly-struct.cpp 69 | - Poly: src/math/Poly.cpp 70 | - PowerfulNumber: src/math/PowerfulNumber.cpp 71 | - Simplex: src/math/Simplex.cpp 72 | - SimpsonIntegral: src/math/SimpsonIntegral.cpp 73 | other: 74 | - BFPRT: src/other/BFPRT.cpp 75 | - cpp-header: src/other/cpp-header.cpp 76 | - debug: src/other/debug.h 77 | - java-header: src/other/java-header.java 78 | - SimulateAnneal: src/other/SimulateAnneal.cpp 79 | string: 80 | - ACAM: src/string/ACAM.cpp 81 | - GSAM: src/string/GSAM.cpp 82 | - KMP: src/string/KMP.cpp 83 | - Manacher: src/string/Manacher.cpp 84 | - PAM: src/string/PAM.cpp 85 | - SA: src/string/SA.cpp 86 | - SAIS: src/string/SAIS.cpp 87 | - SAM: src/string/SAM.cpp 88 | - SqAM: src/string/SqAM.cpp 89 | - string-hash: src/string/string-hash.cpp 90 | - SuffixBST: src/string/SuffixBST.cpp 91 | - Trie: src/string/Trie.cpp 92 | - ZAlgorithm: src/string/ZAlgorithm.cpp 93 | -------------------------------------------------------------------------------- /tex/head: -------------------------------------------------------------------------------- 1 | %==============================常用宏包、环境==============================% 2 | \documentclass[a4]{article} 3 | \usepackage{xeCJK} % For Chinese characters 4 | \usepackage{amsmath, amsthm} 5 | \usepackage[cache=false, outputdir=build]{minted} % 代码插入与高亮 6 | \usepackage{geometry} % 设置页边距 7 | \usepackage{fontspec} 8 | \usepackage{graphicx} 9 | \usepackage{fancyhdr} % 自定义页眉页脚 10 | \usepackage[colorlinks]{hyperref} % 目录超链接 11 | \setsansfont{Consolas} % 设置英文字体 12 | \setmonofont[Mapping={}]{Consolas} % 英文引号之类的正常显示,相当于设置英文字体 13 | \geometry{left=1cm,right=1cm,top=2cm,bottom=0.5cm} % 页边距 14 | % \setlength{\columnsep}{30pt} 15 | % \setlength\columnseprule{0.4pt} % 分割线 16 | %==============================常用宏包、环境==============================% 17 | 18 | %==============================页眉、页脚==============================% 19 | % 页眉、页脚设置 20 | \pagestyle{fancy} 21 | % \lhead{CUMTB} 22 | \lhead{\CJKfamily{hei} Backlight's Code Template} 23 | \chead{} 24 | % \rhead{Page \thepage} 25 | \rhead{\CJKfamily{hei} 第 \thepage 页} 26 | \lfoot{} 27 | \cfoot{} 28 | \rfoot{} 29 | \renewcommand{\headrulewidth}{0.4pt} 30 | \renewcommand{\footrulewidth}{0.4pt} 31 | %==============================页眉、页脚==============================% 32 | 33 | %==============================标题和目录==============================% 34 | \title{\CJKfamily{hei} \bfseries Backlight's Code Template} 35 | \author{Backlight @ CSU} 36 | \renewcommand{\today}{\number\year 年 \number\month 月 \number\day 日} 37 | 38 | \begin{document}\small 39 | \begin{titlepage} 40 | \maketitle 41 | \end{titlepage} 42 | 43 | \newpage 44 | \pagestyle{empty} 45 | \renewcommand{\contentsname}{目录} 46 | \tableofcontents 47 | \newpage\clearpage 48 | \newpage 49 | \pagestyle{fancy} 50 | \setcounter{page}{1} %new page 51 | %==============================标题和目录==============================% 52 | 53 | 54 | %==============================正文部分==============================% 55 | 56 | -------------------------------------------------------------------------------- /tex/tail: -------------------------------------------------------------------------------- 1 | 2 | %==============================正文部分==============================% 3 | \end{document} --------------------------------------------------------------------------------