From aad5f9afae9c9c686a575513616131690e70ed7d Mon Sep 17 00:00:00 2001 From: luizacbcampos Date: Tue, 7 May 2024 11:22:25 -0300 Subject: [PATCH 01/43] Fix for MacOS --- .gitignore | 74 ++++++++++++++++++++++++++++++++++++++++++++++ README.md | 31 +++++++++++++++---- latex/getlatex.cpp | 9 ++++-- latex/getlatex.sh | 3 ++ 4 files changed, 109 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 4aa3a38..ac30ec3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,77 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +# Visual Studio Code +.vscode/ +# Local History for Visual Studio Code +.history/ +# Built Visual Studio Code Extensions +*.vsix +## User settings +xcuserdata/ + +## Xcode 8 and earlier +*.xcscmblueprint +*.xccheckout + +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + *~ latex/biblioteca.tex latex/biblioteca.log +latex/getlatex \ No newline at end of file diff --git a/README.md b/README.md index c823e4e..72c5960 100644 --- a/README.md +++ b/README.md @@ -4,23 +4,42 @@ Biblioteca de algoritmos, estruturas de dados e primitivas para Maratona de Prog Códigos em C++, em maior parte implementados pelos alunos da universidade. -#### PDF +### PDF Versão em PDF dos algoritmos pode ser encontrada [aqui](https://github.com/brunomaletta/Biblioteca/blob/master/pdf/biblioteca.pdf). +O *theoretical guide* (documento com teoremas, identidades e informações teóricas relevantes) pode ser encontrado [aqui](https://github.com/brunomaletta/Biblioteca/blob/master/pdf/theoretical.pdf). + +Link para o latex do theoretical: [link](https://www.overleaf.com/read/xrbtzvvkmkxs). + +#### Atualizar o PDF + +
+Detalhes + Para atualizar o PDF primeiro instale o latex executando ``` sudo apt install texlive-full -sudo apt install rubber ``` -e então execute `./getlatex.sh` na pasta latex. +O pdf é gerado usando a ferramenta [rubber](https://gitlab.com/latex-rubber/rubber). Para baixá-la execute: +``` +sudo apt install rubber +``` +ou +``` +pip install latex-rubber +``` -O *theoretical guide* (documento com teoremas, identidades e informações teóricas relevantes) pode ser encontrado [aqui](https://github.com/brunomaletta/Biblioteca/blob/master/pdf/theoretical.pdf). +Por fim, execute -Link para o latex do theoretical: [link](https://www.overleaf.com/read/xrbtzvvkmkxs). +``` +cd latex +./getlatex.sh +``` +
-#### Hash +### Hash No PDF, a coluna de hash é o hash de cada linha, exceto se a linha contem um caractere `}`. Nesse caso, o hash da linha é o hash a partir da linha que fecha o último `}` da linha atual. diff --git a/latex/getlatex.cpp b/latex/getlatex.cpp index f8e9c62..0af23bb 100644 --- a/latex/getlatex.cpp +++ b/latex/getlatex.cpp @@ -13,8 +13,13 @@ string NO_HASH = "nohash"; string NO_PRINT = "noprint"; string path = "../Codigo/"; +#ifdef __clang__ +string hash_cmd = "sed -n 1','10000' p' tmp.cpp | sed '/^#w/d' " + "| clang -E -x c++ -dD -P - | tr -d '[:space:]' | md5sum | cut -c-"; +#else string hash_cmd = "sed -n 1','10000' p' tmp.cpp | sed '/^#w/d' " "| cpp -dD -P -fpreprocessed | tr -d '[:space:]' | md5sum | cut -c-"; +#endif bool print_all = false; @@ -199,7 +204,7 @@ void dfs(vector>& files, string s, bool extra = false) { struct dirent* entry = nullptr; DIR* dp = nullptr; dp = opendir(s.c_str()); - if (dp != nullptr) while (entry = readdir(dp)) { + if (dp != nullptr) while ((entry = readdir(dp))) { if (entry->d_name[0] == '.') continue; if (entry->d_type == DT_DIR) dfs(files, s + "/" + string(entry->d_name), extra); @@ -242,7 +247,7 @@ int main(int argc, char** argv) { struct dirent* entry = nullptr; DIR* dp = nullptr; dp = opendir(path.c_str()); - if (dp != nullptr) while (entry = readdir(dp)) { + if (dp != nullptr) while ((entry = readdir(dp))) { if (entry->d_name[0] == '.') continue; if (entry->d_type != DT_DIR) continue; diff --git a/latex/getlatex.sh b/latex/getlatex.sh index b7c101e..a2818de 100755 --- a/latex/getlatex.sh +++ b/latex/getlatex.sh @@ -1,6 +1,9 @@ +#!/bin/bash + g++ -std=c++17 -o getlatex getlatex.cpp -O2 ./getlatex $1 > biblioteca.tex rubber -d biblioteca mv biblioteca.pdf ../pdf rm tmp.cpp rm getlatex biblioteca.aux biblioteca.toc biblioteca.out +rm -f biblioteca.rubbercache From 0c140d1956e62fd4b5e390b774bb6524e6253427 Mon Sep 17 00:00:00 2001 From: luizacbcampos Date: Tue, 7 May 2024 18:31:43 -0300 Subject: [PATCH 02/43] generate documentation --- docs/gendocs.cpp | 323 +++++++++++++++++++++++++++++++++++++++++++++++ docs/gendocs.sh | 5 + 2 files changed, 328 insertions(+) create mode 100644 docs/gendocs.cpp create mode 100755 docs/gendocs.sh diff --git a/docs/gendocs.cpp b/docs/gendocs.cpp new file mode 100644 index 0000000..dd1bcd2 --- /dev/null +++ b/docs/gendocs.cpp @@ -0,0 +1,323 @@ +#include +#include + +namespace fs = std::filesystem; +using namespace std; + +#define RED "\033[0;31m" +#define RESET "\033[0m" +#define CYAN "\033[0;36m" +#define BOLD "\033[1m" +#define NO_BOLD "\033[0m" + +bool LOOK_FOR_HASH_IN_FILE = false; +int HASH_LEN = 3; + +string NO_HASH = "nohash"; +string NO_PRINT = "noprint"; + +string PATH = "../Codigo/"; +string docs_path = "../content/docs/"; +string link = "https://github.com/brunomaletta/Biblioteca/tree/master/"; + +#ifdef __clang__ +string hash_cmd = "sed -n 1','10000' p' tmp.cpp | sed '/^#w/d' " + "| clang -E -x c++ -dD -P - | tr -d '[:space:]' | md5sum | cut -c-"; +#else +string hash_cmd = "sed -n 1','10000' p' tmp.cpp | sed '/^#w/d' " +"| cpp -dD -P -fpreprocessed | tr -d '[:space:]' | md5sum | cut -c-"; +#endif + +bool print_all = false; +bool overwrite = false; + +void strip(string& str) { + if (str.length() == 0) return; + + auto start_it = str.begin(); + auto end_it = str.rbegin(); + while (isspace(*start_it)) { + ++start_it; + if (start_it == str.end()) break; + } + while (isspace(*end_it)) { + ++end_it; + if (end_it == str.rend()) break; + } + int start_pos = start_it - str.begin(); + int end_pos = end_it.base() - str.begin(); + str = start_pos <= end_pos ? string(start_it, end_it.base()) : ""; +} + + +bool is_comment(string line) { + while (line.size() and (line[0] == ' ' or line[0] == '\t')) + line = line.substr(1); + bool comment = line.size() == 0; + if (line.size() >= 2 and line.substr(0, 2) == "//") comment = true; + if (line.size() >= 2 and line.substr(0, 2) == "/*") comment = true; + return comment; +} + +void remove_comment(string &line){ + if (line.size() >= 2 and line.substr(0, 2) == "//") + line = line.substr(2); + if (line.size() >= 2 and line.substr(0, 2) == "/*") + line = line.substr(2); + if (line.size() >= 2 and line.substr(line.size() - 2, 2) == "*/") + line = line.substr(0, line.size() - 2); +} + +vector split(string line, char c) { + vector ret; + string cur; + line.push_back(c); + for (char at : line) { + if (at == c) { + if (cur.size()) ret.push_back(cur); + cur.clear(); + continue; + } + cur += at; + } + return ret; +} + +set get_flags(string file) { + ifstream fin(file.c_str()); + string line; + getline(fin, line); + fin.close(); + while (line.size() and line[0] != '[') line = line.substr(1); + if (!line.size() or line.back() != ']') return {}; + vector flags = split(line.substr(1, line.size() - 2), ','); + return set(flags.begin(), flags.end()); +} + +void remove_flags(string& line) { + int has_flags = 0; + for (char c : line) { + if (has_flags == 0 and c == '[') has_flags++; + if (has_flags == 1 and c == ']') has_flags++; + } + if (has_flags != 2) return; + int idx = -1; + for (int i = 0; i < line.size(); i++) if (line[i] == '[') { + idx = i; + break; + } + while (line.size() > idx) line.pop_back(); + while (line.size() and line.back() == ' ') line.pop_back(); +} + +pair, vector> get_code(string file){ + ifstream fin(file.c_str()); + string line; + int count = 0; + bool started_code = false; + int depth = 0; + stack st; + vector comment_lines; + vector code_lines; + for (int line_idx = 0; getline(fin, line); line_idx++) { + int start_line = line_idx; + if (count++ < 2) continue; + + for (char c : line) { + if (c == '{') depth++, st.push(line_idx); + if (c == '}') depth--, start_line = st.top(), st.pop(); + } + + bool comment = is_comment(line); + if (!comment) started_code = true; + if (started_code) { + code_lines.push_back(line); + } else { + comment_lines.push_back(line); + } + } + fin.close(); + + return {comment_lines, code_lines}; +} + + +string get_name(string file) { + ifstream fin(file.c_str()); + string line; + getline(fin, line); + fin.close(); + remove_flags(line); + if (line[2] == ' ') return line.substr(3); + return line.substr(2); +} + +void dfs(vector>& files, string s, bool extra = false) { + struct dirent* entry = nullptr; + DIR* dp = nullptr; + dp = opendir(s.c_str()); + if (dp != nullptr) while ((entry = readdir(dp))) { + if (entry->d_name[0] == '.') continue; + + if (entry->d_type == DT_DIR) dfs(files, s + "/" + string(entry->d_name), extra); + else { + files.emplace_back(entry->d_name, s + "/" + string(entry->d_name)); + } + } +} + +string lower(string s) { + for (char& c : s) if (c >= 'A' and c <= 'Z') c ^= 32; + return s; +} + +time_t get_current_time(){ + auto now = std::chrono::system_clock::now(); + return std::chrono::system_clock::to_time_t(now); +} + +string time_to_string(time_t time, string format = "%Y-%m-%dT%H:%M:%S%z"){ + std::tm* now_tm = std::localtime(&time); + // Format the time using stringstream + std::stringstream ss; + ss << std::put_time(now_tm, format.c_str()); + return ss.str(); +} + +string get_docs_path(string code_path) { + code_path.replace(code_path.find(".cpp"), sizeof(".cpp") - 1, ".md"); + code_path.erase(0, PATH.size()); + code_path.insert(0, docs_path); + return code_path; +} + +string get_original_link(string path_code) { + // Remove '../' from path_code + path_code.replace(path_code.find("../"), sizeof("../") - 1, ""); + return link + path_code; +} + +void create_code_file(string path_docs, string path_code, string title) { + // pair < comments, code > + pair, vector> code = get_code(path_code); + + ofstream out(path_docs); + out << "---" << endl; + out << "weight: 10" << endl; + out << "title: \"" << title << "\"\n"; + out << "draft: false" << endl; + out << "toc: true" << endl; + out << "date: \"" << time_to_string(get_current_time()) << "\"" << endl; + out << "publishdate: \"" << time_to_string(get_current_time()) << "\"" << endl; + out << "description: " << "\"\"" << endl; + out << "---" << endl << endl; + + out << "## Sobre" << endl; + for (auto line : code.first) { + remove_comment(line); + out << line << endl << endl; + } + + string full_link = get_original_link(path_code); + string short_link = full_link.substr(full_link.find_last_of("/") + 1); + + out << "Link original: [" << short_link << "](" << full_link << ")" << endl; + out << endl; + + out << "## Código" << endl; + out << "```cpp" << endl; + for (auto line : code.second) { + out << line << endl; + } + out << "```" << endl; + out.close(); +} + +void create_default_index(string path_index, string index_title) { + string date = time_to_string(get_current_time()); + + ofstream out(path_index); + out << "---" << endl; + out << "weight: 10" << endl; + out << "title: \"" << index_title << "\"\n"; + out << "draft: false" << endl; + // out << "toc: true" << endl; + out << "date: \"" << date << "\"" << endl; + out << "description: " << "\"\"" << endl; + out << "publishdate: \"" << date << "\"" << endl; + out << "---" << endl; + out.close(); +} + +void create_section(string path) { + // Check if directory exists + string dir = docs_path + path; + if (fs::is_directory(fs::path(dir))){ + // Check if dir + '/_index.md' exists + string index = dir + "/_index.md"; + if (!fs::exists(fs::path(index))) { + cerr << "Creating index file: " << index << endl; + create_default_index(index, path); + } + } + else { + cerr << "Creating directory: " << dir << endl; + fs::create_directory(fs::path(dir)); + // print type of dir + string index = dir + "/_index.md"; + create_default_index(index, path); + } +} + +int main(int argc, char** argv) { + if (argc > 1) { + string arg1(argv[1]); + if (arg1 == "--overwrite") { + overwrite = true; + cerr << "Rewriting all docs files..." << endl << endl; + } + } + + struct dirent* entry = nullptr; + DIR* dp = nullptr; + dp = opendir(PATH.c_str()); + if (dp != nullptr) while ((entry = readdir(dp))) { + if (entry->d_name[0] == '.') continue; + if (entry->d_type != DT_DIR) continue; + + string dir(entry->d_name); + cout << RED << "=== " << dir << " ===" << RESET << endl; + create_section(dir); + if (dir == "Extra") continue; + + vector> files; + dfs(files, PATH + dir); + + // print all files + for (auto [f, f_path] : files) { + string title = get_name(f_path); + strip(title); + string path_docs = get_docs_path(f_path); + cout << CYAN << "\t" << title << RESET << endl; + cerr << "\t" << f_path << " -> " << path_docs << endl; + + if (overwrite) { + create_code_file(path_docs, f_path, title); + } + else{ + if (!fs::exists(fs::path(path_docs))) { + create_code_file(path_docs, f_path, title); + } + else { + cerr << "File already exists: " << path_docs << endl; + } + } + } + } + + // printa_section("Extra"); + vector> files; + // dfs(files, path + "Extra", true); + + return 0; +} diff --git a/docs/gendocs.sh b/docs/gendocs.sh new file mode 100755 index 0000000..e12c256 --- /dev/null +++ b/docs/gendocs.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +g++ -std=c++17 -o gendocs gendocs.cpp -O2 +./gendocs $1 +rm gendocs From 776fe02e2111129640fed02172b3643f4f9d6161 Mon Sep 17 00:00:00 2001 From: luizacbcampos Date: Tue, 7 May 2024 18:59:27 -0300 Subject: [PATCH 03/43] Hugo basics --- .hugo_build.lock | 0 go.sum | 8 +++ hugo.toml | 160 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 168 insertions(+) create mode 100644 .hugo_build.lock create mode 100644 go.sum create mode 100644 hugo.toml diff --git a/.hugo_build.lock b/.hugo_build.lock new file mode 100644 index 0000000..e69de29 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..d56dc0e --- /dev/null +++ b/go.sum @@ -0,0 +1,8 @@ +github.com/colinwilson/lotusdocs v0.1.0 h1:oTC8pAYQp9XDNaUwE4SEY+id3ByNELxIIFrktYEGxYA= +github.com/colinwilson/lotusdocs v0.1.0/go.mod h1:9zu2REJDi+zdPRcR5/bRYSUR7gkNF4NQLvV38SEoCP8= +github.com/colinwilson/lotusdocs v0.1.1-0.20231204194117-128b0ae80b44 h1:EpDUXuqD2dINvcl0PLCjSAkwEsL8ECeIeTXTqHaBKmc= +github.com/colinwilson/lotusdocs v0.1.1-0.20231204194117-128b0ae80b44/go.mod h1:9zu2REJDi+zdPRcR5/bRYSUR7gkNF4NQLvV38SEoCP8= +github.com/gohugoio/hugo-mod-bootstrap-scss/v5 v5.20300.20200 h1:SmpwwN3DNzJWbV+IT8gaFu07ENUFpCvKou5BHYUKuVs= +github.com/gohugoio/hugo-mod-bootstrap-scss/v5 v5.20300.20200/go.mod h1:kx8MBj9T7SFR8ZClWvKZPmmUxBaltkoXvnWlZZcSnYA= +github.com/gohugoio/hugo-mod-jslibs-dist/popperjs/v2 v2.21100.20000/go.mod h1:mFberT6ZtcchrsDtfvJM7aAH2bDKLdOnruUHl0hlapI= +github.com/twbs/bootstrap v5.3.2+incompatible/go.mod h1:fZTSrkpSf0/HkL0IIJzvVspTt1r9zuf7XlZau8kpcY0= diff --git a/hugo.toml b/hugo.toml new file mode 100644 index 0000000..e142f54 --- /dev/null +++ b/hugo.toml @@ -0,0 +1,160 @@ +baseURL = "/" # (or set via env variable HUGO_BASEURL) +languageCode = "pt-BR" +title = "Biblioteca" +contentDir = "content" +enableEmoji = true + +defaultContentLanguage = 'pt' +[languages] + [languages.pt] + title = "Lotus Docs Example Site" + languageName = "Português" + weight = 10 + # [languages.fr] + # title = "Lotus Docs Exemple de Site" + # languageName = "Français" + # contentDir = "content/fr" + # weight = 20 + +[module] + [module.hugoVersion] + extended = true + min = "0.100.0" + [[module.imports]] + path = "github.com/colinwilson/lotusdocs" + disable = false + [[module.imports]] + path = "github.com/gohugoio/hugo-mod-bootstrap-scss/v5" + disable = false + +[markup] + [markup.tableOfContents] + endLevel = 3 + startLevel = 1 + [markup.goldmark] + [markup.goldmark.renderer] + unsafe = true # https://jdhao.github.io/2019/12/29/hugo_html_not_shown/ + # [markup.highlight] + # codeFences = false # disables Hugo's default syntax highlighting + [markup.goldmark.parser] + [markup.goldmark.parser.attribute] + block = true + +[params] + + # Google Fonts + google_fonts = [ + ["Inter", "300, 400, 600, 700"], + ["Fira Code", "500, 700"] + ] + + sans_serif_font = "Inter" # Default is System font + secondary_font = "Inter" # Default is System font + mono_font = "Fira Code" # Default is System font + + [params.footer] + copyright = "© :YEAR:. Built with [**Lotus Docs**](https://github.com/colinwilson/lotusdocs)" + version = true # include git commit info in footer + + [params.social] + github = "brunomaletta/Biblioteca" # github.com/YOUR_GITHUB_ID + # twitter = "" # twitter.com/YOUR_TWITTER_ID + # instagram = "" # instagram.com/YOUR_INSTAGRAM_ID + # rss = true # show rss icon with link + + [params.docs] # Parameters for the /docs 'template' + title = "Docs" # default html title for documentation pages/sections + + # pathName = "docs" # path for documentation site | default "docs" + + themeColor = "red" # (optional) - Set theme accent colour. Options include: blue (default), green, red, yellow, emerald, cardinal, magenta, cyan + + darkMode = true # enable dark mode option? default false + + prism = true # enable syntax highlighting via Prism + + prismTheme = "lotusdocs" # (optional) - Set theme for PrismJS. Options include: lotusdocs (default), solarized-light, twilight, lucario + +# # gitinfo + repoURL = "https://github.com/brunomaletta/Biblioteca" # Git repository URL for your site [support for GitHub, GitLab, and BitBucket] + repoBranch = "release" # Name of your Git repository branch + editPage = true # enable 'Edit this page' feature - default false + lastMod = true # enable 'Last modified' date on pages - default false + lastModRelative = true # format 'Last modified' time as relative - default true + + # ToC + toc = true # enable table of contents? default is true + tocMobile = true # enable table of contents in mobile view? default is true + scrollSpy = true # enable scrollspy on ToC? default is true + + # icons + sidebarIcons = true # enable sidebar icons? default false + titleIcon = true # enable front matter icon title prefix? default is false + + # content navigation + breadcrumbs = true # default is true + navDesc = true # include front matter descriptions in Prev/Next navigation cards + navDescTrunc = 30 # Number of characters by which to truncate the Prev/Next descriptions + + listDescTrunc = 100 # Number of characters by which to truncate the list card description + backToTop = true # enable back-to-top button? default true + + # front matter + descriptions = true # enable front matter descriptions under content title? + + # Link behaviour + intLinkTooltip = true # Enable a tooltip for internal links that displays info about the destination? default false + extLinkNewTab = true # Open external links in a new Tab? default true + # logoLinkURL = "" # Set a custom URL destination for the top header logo link. + + [params.flexsearch] # Parameters for FlexSearch + enabled = true + # tokenize = "full" + # optimize = true + # cache = 100 + # minQueryChar = 3 # default is 0 (disabled) + # maxResult = 5 # default is 5 + # searchSectionsIndex = [] + + [params.feedback] + enabled = false +# emoticonTpl = true +# eventDest = ["plausible","google"] +# emoticonEventName = "Feedback" +# positiveEventName = "Positive Feedback" +# negativeEventName = "Negative Feedback" +# positiveFormTitle = "What did you like?" +# negativeFormTitle = "What went wrong?" +# successMsg = "Thank you for helping to improve Lotus Docs' documentation!" +# errorMsg = "Sorry! There was an error while attempting to submit your feedback!" +# positiveForm = [ +# ["Accurate", "Accurately describes the feature or option."], +# ["Solved my problem", "Helped me resolve an issue."], +# ["Easy to understand", "Easy to follow and comprehend."], +# ["Something else"] +# ] +# negativeForm = [ +# ["Inaccurate", "Doesn't accurately describe the feature or option."], +# ["Couldn't find what I was looking for", "Missing important information."], +# ["Hard to understand", "Too complicated or unclear."], +# ["Code sample errors", "One or more code samples are incorrect."], +# ["Something else"] +# ] + +[[menu.primary]] + name = "Docs" + url = "/docs/" + identifier = "docs" + weight = 10 + +# # [[menu.primary]] +# # name = "Showcase" +# # url = "/showcase" +# # identifier = "showcase" +# # weight = 20 + +# [[menu.primary]] +# name = "Community" +# url = "https://github.com/colinwilson/lotusdocs/discussions" +# identifier = "community" +# weight = 30 \ No newline at end of file From c1ac90e66c135d82b96727f813aeabeb51e6fa79 Mon Sep 17 00:00:00 2001 From: luizacbcampos Date: Tue, 7 May 2024 19:13:41 -0300 Subject: [PATCH 04/43] basics --- content/docs/_index.md | 9 +++++++ data/landing.yaml | 59 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 content/docs/_index.md create mode 100644 data/landing.yaml diff --git a/content/docs/_index.md b/content/docs/_index.md new file mode 100644 index 0000000..6b6c079 --- /dev/null +++ b/content/docs/_index.md @@ -0,0 +1,9 @@ +--- +weight: 300 +title: "Biblioteca" +description: "" +icon: "folder" +date: "2024-05-07T00:34:57+01:00" +lastmod: "2024-05-07T00:34:57+01:00" +draft: false +--- \ No newline at end of file diff --git a/data/landing.yaml b/data/landing.yaml new file mode 100644 index 0000000..be2fe75 --- /dev/null +++ b/data/landing.yaml @@ -0,0 +1,59 @@ +# Note: Template blocks require a 'weight' parameter so they're correctly ordered on the landing page + +# Hero +hero: + enable: true + weight: 10 + template: hero + + title: "Biblioteca" + subtitle: Biblioteca de algoritmos, estruturas de dados e primitivas para Maratona de Programação da UFMG. + + backgroundImage: + path: "images/templates/hero" + filename: + desktop: "gradient-desktop.webp" + mobile: "gradient-mobile.webp" + + # titleLogo: + # path: "images/logos" + # filename: "title_logo.png" + # alt: "Lotus Docs Logo" + # height: 80px + + + image: + # path: "images" # path to image under configured assets directory. default 'images' + # filename: "lotus_docs_screenshot.png" # filename of your hero image (including file extension) + # alt: "Lotus Docs Screenshot" # Optional but recommended + boxShadow: false # default 'false' (excludes .svg images) + rounded: false # round the image corners? default 'false' (excludes .svg images) + + # ctaButton: + # icon: rocket_launch + # btnText: "Get Started" + # url: "/docs/quickstart/#create-a-new-lotus-docs-site" + + cta2Button: + icon: library_books + btnText: "Documentação" + url: "/docs" + + info: "**Open Source** MIT Licensed." + +# Feature Grid +featureGrid: + enable: false + weight: 20 + template: feature grid + +imageText: + enable: false + weight: 25 + template: image text + +# Image compare +imageCompare: + enable: false + weight: 30 + template: image compare \ No newline at end of file From f42767ccb53c1bb6ef64569f37ad1c68cb706787 Mon Sep 17 00:00:00 2001 From: luizacbcampos Date: Tue, 7 May 2024 19:24:14 -0300 Subject: [PATCH 05/43] workflow test --- workflow_hugo.yaml | 76 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 workflow_hugo.yaml diff --git a/workflow_hugo.yaml b/workflow_hugo.yaml new file mode 100644 index 0000000..eb6c933 --- /dev/null +++ b/workflow_hugo.yaml @@ -0,0 +1,76 @@ +# Sample workflow for building and deploying a Hugo site to GitHub Pages +name: Deploy Hugo site to Pages + +on: +# Runs on pushes targeting the default branch +push: + branches: + - main + +# Allows you to run this workflow manually from the Actions tab +workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: +contents: read +pages: write +id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: +group: "pages" +cancel-in-progress: false + +# Default to bash +defaults: +run: + shell: bash + +jobs: +# Build job +build: + runs-on: ubuntu-latest + env: + HUGO_VERSION: 0.118.2 + steps: + - name: Install Hugo CLI + run: | + wget -O ${{ runner.temp }}/hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \ + && sudo dpkg -i ${{ runner.temp }}/hugo.deb + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + - name: Setup Pages + id: pages + uses: actions/configure-pages@v3 + - name: Install Node.js dependencies + run: "[[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true" + - name: Build with Hugo + env: + # For maximum backward compatibility with Hugo modules + HUGO_ENVIRONMENT: production + HUGO_ENV: production + run: | + hugo \ + --gc \ + --minify \ + --baseURL "${{ steps.pages.outputs.base_url }}/" + - name: Upload artifact + uses: actions/upload-pages-artifact@v1 + with: + path: ./public + +# Deployment job +deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v2 \ No newline at end of file From 63f93400e3f9a2a50d07603c788b19bf6b39c2b8 Mon Sep 17 00:00:00 2001 From: Luiza Campos Date: Tue, 7 May 2024 19:26:03 -0300 Subject: [PATCH 06/43] Create hugo.yml --- .github/workflows/hugo.yml | 76 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 .github/workflows/hugo.yml diff --git a/.github/workflows/hugo.yml b/.github/workflows/hugo.yml new file mode 100644 index 0000000..347cdfe --- /dev/null +++ b/.github/workflows/hugo.yml @@ -0,0 +1,76 @@ +# Sample workflow for building and deploying a Hugo site to GitHub Pages +name: Deploy Hugo site to Pages + +on: +# Runs on pushes targeting the default branch +push: + branches: + - main + +# Allows you to run this workflow manually from the Actions tab +workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: +contents: read +pages: write +id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: +group: "pages" +cancel-in-progress: false + +# Default to bash +defaults: +run: + shell: bash + +jobs: +# Build job +build: + runs-on: ubuntu-latest + env: + HUGO_VERSION: 0.118.2 + steps: + - name: Install Hugo CLI + run: | + wget -O ${{ runner.temp }}/hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \ + && sudo dpkg -i ${{ runner.temp }}/hugo.deb + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + - name: Setup Pages + id: pages + uses: actions/configure-pages@v3 + - name: Install Node.js dependencies + run: "[[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true" + - name: Build with Hugo + env: + # For maximum backward compatibility with Hugo modules + HUGO_ENVIRONMENT: production + HUGO_ENV: production + run: | + hugo \ + --gc \ + --minify \ + --baseURL "${{ steps.pages.outputs.base_url }}/" + - name: Upload artifact + uses: actions/upload-pages-artifact@v1 + with: + path: ./public + +# Deployment job +deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v2 From feead903dfcbf3c8a1e31c10d18241c492d79f02 Mon Sep 17 00:00:00 2001 From: Luiza Campos Date: Tue, 7 May 2024 19:32:59 -0300 Subject: [PATCH 07/43] Update hugo.yml --- .github/workflows/hugo.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/hugo.yml b/.github/workflows/hugo.yml index 347cdfe..7c561e4 100644 --- a/.github/workflows/hugo.yml +++ b/.github/workflows/hugo.yml @@ -5,7 +5,7 @@ on: # Runs on pushes targeting the default branch push: branches: - - main + - master # Allows you to run this workflow manually from the Actions tab workflow_dispatch: @@ -37,7 +37,7 @@ build: - name: Install Hugo CLI run: | wget -O ${{ runner.temp }}/hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \ - && sudo dpkg -i ${{ runner.temp }}/hugo.deb + && sudo dpkg -i ${{ runner.temp }}/hugo.deb - name: Checkout uses: actions/checkout@v4 with: From cb3d620a4e72d106b3702cdf79419ea4c90e95c6 Mon Sep 17 00:00:00 2001 From: Luiza Campos Date: Tue, 7 May 2024 19:37:50 -0300 Subject: [PATCH 08/43] Update hugo.yml --- .github/workflows/hugo.yml | 101 +++++++++++++++---------------------- 1 file changed, 41 insertions(+), 60 deletions(-) diff --git a/.github/workflows/hugo.yml b/.github/workflows/hugo.yml index 7c561e4..1ffbe49 100644 --- a/.github/workflows/hugo.yml +++ b/.github/workflows/hugo.yml @@ -1,76 +1,57 @@ -# Sample workflow for building and deploying a Hugo site to GitHub Pages name: Deploy Hugo site to Pages on: -# Runs on pushes targeting the default branch -push: + push: branches: - - master + - master -# Allows you to run this workflow manually from the Actions tab -workflow_dispatch: - -# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages -permissions: -contents: read -pages: write -id-token: write - -# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. -# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. -concurrency: -group: "pages" -cancel-in-progress: false - -# Default to bash -defaults: -run: - shell: bash + # Allows manual triggering from the Actions tab + workflow_dispatch: jobs: -# Build job -build: + build: runs-on: ubuntu-latest env: - HUGO_VERSION: 0.118.2 + HUGO_VERSION: 0.118.2 steps: - - name: Install Hugo CLI - run: | - wget -O ${{ runner.temp }}/hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \ - && sudo dpkg -i ${{ runner.temp }}/hugo.deb - - name: Checkout - uses: actions/checkout@v4 + - name: Checkout repository + uses: actions/checkout@v2 with: - submodules: recursive - fetch-depth: 0 - - name: Setup Pages - id: pages - uses: actions/configure-pages@v3 - - name: Install Node.js dependencies - run: "[[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true" - - name: Build with Hugo - env: - # For maximum backward compatibility with Hugo modules - HUGO_ENVIRONMENT: production - HUGO_ENV: production - run: | - hugo \ - --gc \ - --minify \ - --baseURL "${{ steps.pages.outputs.base_url }}/" - - name: Upload artifact - uses: actions/upload-pages-artifact@v1 + submodules: recursive + fetch-depth: 0 + + - name: Setup Hugo + uses: peaceiris/actions-hugo@v2 + with: + hugo-version: ${{ env.HUGO_VERSION }} + + - name: Install Node.js dependencies + run: npm ci + + - name: Build site with Hugo + run: hugo --minify --baseURL "${{ steps.pages.outputs.base_url }}/" + + - name: Upload artifact + uses: actions/upload-artifact@v2 with: - path: ./public + name: hugo-site + path: ./public -# Deployment job -deploy: - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} + deploy: runs-on: ubuntu-latest needs: build steps: - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v2 + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Download artifact + uses: actions/download-artifact@v2 + with: + name: hugo-site + path: ./public + + - name: Deploy to GitHub Pages + uses: peaceiris/actions-gh-pages@v3 + with: + deploy_key: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./public From 5625166ba7555b696073e4b85cf2cb3264940a4c Mon Sep 17 00:00:00 2001 From: Luiza Campos Date: Tue, 7 May 2024 19:39:53 -0300 Subject: [PATCH 09/43] Update hugo.yml --- .github/workflows/hugo.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/hugo.yml b/.github/workflows/hugo.yml index 1ffbe49..3beaa2f 100644 --- a/.github/workflows/hugo.yml +++ b/.github/workflows/hugo.yml @@ -26,7 +26,7 @@ jobs: hugo-version: ${{ env.HUGO_VERSION }} - name: Install Node.js dependencies - run: npm ci + run: "[[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true" - name: Build site with Hugo run: hugo --minify --baseURL "${{ steps.pages.outputs.base_url }}/" From 17fb5df85fe78dd985c8d858f73c0bb20fd177f8 Mon Sep 17 00:00:00 2001 From: Luiza Campos Date: Tue, 7 May 2024 20:16:20 -0300 Subject: [PATCH 10/43] Update hugo.yml --- .github/workflows/hugo.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/hugo.yml b/.github/workflows/hugo.yml index 3beaa2f..31611c3 100644 --- a/.github/workflows/hugo.yml +++ b/.github/workflows/hugo.yml @@ -27,6 +27,10 @@ jobs: - name: Install Node.js dependencies run: "[[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true" + + - name: Get Hugo modules + run: | + hugo mod get - name: Build site with Hugo run: hugo --minify --baseURL "${{ steps.pages.outputs.base_url }}/" From 8701cb6ba175b25f0a95d9b35a04674d7b8febe3 Mon Sep 17 00:00:00 2001 From: Luiza Campos Date: Tue, 7 May 2024 20:20:08 -0300 Subject: [PATCH 11/43] Create go.mod --- go.mod | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 go.mod diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..3ef65c0 --- /dev/null +++ b/go.mod @@ -0,0 +1,8 @@ +module github.com/brunomaletta/Biblioteca + +go 1.22.0 + +require ( + github.com/colinwilson/lotusdocs v0.1.1-0.20231204194639-f5785a2399ca // indirect + github.com/gohugoio/hugo-mod-bootstrap-scss/v5 v5.20300.20200 // indirect +) From b85af1e3bff1b50970817af5b265b157252a5958 Mon Sep 17 00:00:00 2001 From: Luiza Campos Date: Tue, 7 May 2024 20:22:29 -0300 Subject: [PATCH 12/43] Update hugo.yml --- .github/workflows/hugo.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/hugo.yml b/.github/workflows/hugo.yml index 31611c3..1f87f16 100644 --- a/.github/workflows/hugo.yml +++ b/.github/workflows/hugo.yml @@ -12,7 +12,7 @@ jobs: build: runs-on: ubuntu-latest env: - HUGO_VERSION: 0.118.2 + HUGO_VERSION: 0.123.3 steps: - name: Checkout repository uses: actions/checkout@v2 @@ -24,6 +24,7 @@ jobs: uses: peaceiris/actions-hugo@v2 with: hugo-version: ${{ env.HUGO_VERSION }} + extended: true - name: Install Node.js dependencies run: "[[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true" From 5a7e05f3c0ccd978eeb1ec21cc837663fd1ba246 Mon Sep 17 00:00:00 2001 From: Luiza Campos Date: Tue, 7 May 2024 20:34:38 -0300 Subject: [PATCH 13/43] Update hugo.yml --- .github/workflows/hugo.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.github/workflows/hugo.yml b/.github/workflows/hugo.yml index 1f87f16..8b826ca 100644 --- a/.github/workflows/hugo.yml +++ b/.github/workflows/hugo.yml @@ -46,15 +46,6 @@ jobs: runs-on: ubuntu-latest needs: build steps: - - name: Checkout repository - uses: actions/checkout@v2 - - - name: Download artifact - uses: actions/download-artifact@v2 - with: - name: hugo-site - path: ./public - - name: Deploy to GitHub Pages uses: peaceiris/actions-gh-pages@v3 with: From 82ba7387f66000e9be986e118b4519a143f0b3b1 Mon Sep 17 00:00:00 2001 From: Luiza Campos Date: Tue, 7 May 2024 20:37:42 -0300 Subject: [PATCH 14/43] remove deploy from actions --- .github/workflows/hugo.yml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/.github/workflows/hugo.yml b/.github/workflows/hugo.yml index 8b826ca..e9f11c7 100644 --- a/.github/workflows/hugo.yml +++ b/.github/workflows/hugo.yml @@ -41,13 +41,3 @@ jobs: with: name: hugo-site path: ./public - - deploy: - runs-on: ubuntu-latest - needs: build - steps: - - name: Deploy to GitHub Pages - uses: peaceiris/actions-gh-pages@v3 - with: - deploy_key: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./public From 8881dcfb662f70b4de6b100cd9a6820f06a04b00 Mon Sep 17 00:00:00 2001 From: Luiza Campos Date: Tue, 7 May 2024 20:41:35 -0300 Subject: [PATCH 15/43] Update hugo.yml --- .github/workflows/hugo.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/hugo.yml b/.github/workflows/hugo.yml index e9f11c7..ac272da 100644 --- a/.github/workflows/hugo.yml +++ b/.github/workflows/hugo.yml @@ -41,3 +41,14 @@ jobs: with: name: hugo-site path: ./public +# Deployment job + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 From c72a653a74170313adc75fe9f49c2c12992c2abb Mon Sep 17 00:00:00 2001 From: Luiza Campos Date: Tue, 7 May 2024 20:47:57 -0300 Subject: [PATCH 16/43] Update hugo.yml --- .github/workflows/hugo.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/hugo.yml b/.github/workflows/hugo.yml index ac272da..b9ae380 100644 --- a/.github/workflows/hugo.yml +++ b/.github/workflows/hugo.yml @@ -7,6 +7,17 @@ on: # Allows manual triggering from the Actions tab workflow_dispatch: +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: "pages" + cancel-in-progress: false jobs: build: From 415a4e30a7300a756a820cba98fb99b6f2b2e787 Mon Sep 17 00:00:00 2001 From: Luiza Campos Date: Tue, 7 May 2024 20:53:50 -0300 Subject: [PATCH 17/43] Update hugo.yml --- .github/workflows/hugo.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/hugo.yml b/.github/workflows/hugo.yml index b9ae380..b4ab88e 100644 --- a/.github/workflows/hugo.yml +++ b/.github/workflows/hugo.yml @@ -48,7 +48,7 @@ jobs: run: hugo --minify --baseURL "${{ steps.pages.outputs.base_url }}/" - name: Upload artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: hugo-site path: ./public From 6506e58809ca0ee16f673dbed98bc42ffd9138af Mon Sep 17 00:00:00 2001 From: Luiza Campos Date: Tue, 7 May 2024 20:59:13 -0300 Subject: [PATCH 18/43] Update hugo.yml --- .github/workflows/hugo.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/hugo.yml b/.github/workflows/hugo.yml index b4ab88e..b610682 100644 --- a/.github/workflows/hugo.yml +++ b/.github/workflows/hugo.yml @@ -26,7 +26,7 @@ jobs: HUGO_VERSION: 0.123.3 steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: submodules: recursive fetch-depth: 0 @@ -50,7 +50,6 @@ jobs: - name: Upload artifact uses: actions/upload-artifact@v4 with: - name: hugo-site path: ./public # Deployment job deploy: From 09fb825b855cc8e7eeb9ff7d6741b6e727169718 Mon Sep 17 00:00:00 2001 From: Luiza Campos Date: Tue, 7 May 2024 21:02:19 -0300 Subject: [PATCH 19/43] Update hugo.yml --- .github/workflows/hugo.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/hugo.yml b/.github/workflows/hugo.yml index b610682..47d1371 100644 --- a/.github/workflows/hugo.yml +++ b/.github/workflows/hugo.yml @@ -50,6 +50,7 @@ jobs: - name: Upload artifact uses: actions/upload-artifact@v4 with: + name: github-pages path: ./public # Deployment job deploy: From 88e69565227850b533c56e7a2ec740c2d9943aca Mon Sep 17 00:00:00 2001 From: Luiza Campos Date: Tue, 7 May 2024 21:06:59 -0300 Subject: [PATCH 20/43] Update hugo.toml --- hugo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hugo.toml b/hugo.toml index e142f54..c3d2646 100644 --- a/hugo.toml +++ b/hugo.toml @@ -1,4 +1,4 @@ -baseURL = "/" # (or set via env variable HUGO_BASEURL) +baseURL = "https://luizacbcampos.github.io/Biblioteca" # (or set via env variable HUGO_BASEURL) languageCode = "pt-BR" title = "Biblioteca" contentDir = "content" @@ -157,4 +157,4 @@ defaultContentLanguage = 'pt' # name = "Community" # url = "https://github.com/colinwilson/lotusdocs/discussions" # identifier = "community" -# weight = 30 \ No newline at end of file +# weight = 30 From 216dfd0bba3b5d6e4a126e1c416a70309e138c88 Mon Sep 17 00:00:00 2001 From: Luiza Campos Date: Tue, 7 May 2024 21:11:02 -0300 Subject: [PATCH 21/43] Update hugo.yml --- .github/workflows/hugo.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/hugo.yml b/.github/workflows/hugo.yml index 47d1371..73b2d3b 100644 --- a/.github/workflows/hugo.yml +++ b/.github/workflows/hugo.yml @@ -46,12 +46,12 @@ jobs: - name: Build site with Hugo run: hugo --minify --baseURL "${{ steps.pages.outputs.base_url }}/" - + - name: Upload artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-pages-artifact@v3 with: - name: github-pages path: ./public + # Deployment job deploy: environment: From b3a9041eae0a454fde6abb8eea5a64b1b86b6563 Mon Sep 17 00:00:00 2001 From: luizacbcampos Date: Tue, 7 May 2024 21:35:33 -0300 Subject: [PATCH 22/43] clean up --- go.sum | 2 ++ workflow_hugo.yaml | 76 ---------------------------------------------- 2 files changed, 2 insertions(+), 76 deletions(-) delete mode 100644 workflow_hugo.yaml diff --git a/go.sum b/go.sum index d56dc0e..0a5b679 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ github.com/colinwilson/lotusdocs v0.1.0 h1:oTC8pAYQp9XDNaUwE4SEY+id3ByNELxIIFrkt github.com/colinwilson/lotusdocs v0.1.0/go.mod h1:9zu2REJDi+zdPRcR5/bRYSUR7gkNF4NQLvV38SEoCP8= github.com/colinwilson/lotusdocs v0.1.1-0.20231204194117-128b0ae80b44 h1:EpDUXuqD2dINvcl0PLCjSAkwEsL8ECeIeTXTqHaBKmc= github.com/colinwilson/lotusdocs v0.1.1-0.20231204194117-128b0ae80b44/go.mod h1:9zu2REJDi+zdPRcR5/bRYSUR7gkNF4NQLvV38SEoCP8= +github.com/colinwilson/lotusdocs v0.1.1-0.20231204194639-f5785a2399ca h1:wIxlPGv2c8PCBEGMCXS7CYTLq0sPfWxTTTJg+wgNeec= +github.com/colinwilson/lotusdocs v0.1.1-0.20231204194639-f5785a2399ca/go.mod h1:9zu2REJDi+zdPRcR5/bRYSUR7gkNF4NQLvV38SEoCP8= github.com/gohugoio/hugo-mod-bootstrap-scss/v5 v5.20300.20200 h1:SmpwwN3DNzJWbV+IT8gaFu07ENUFpCvKou5BHYUKuVs= github.com/gohugoio/hugo-mod-bootstrap-scss/v5 v5.20300.20200/go.mod h1:kx8MBj9T7SFR8ZClWvKZPmmUxBaltkoXvnWlZZcSnYA= github.com/gohugoio/hugo-mod-jslibs-dist/popperjs/v2 v2.21100.20000/go.mod h1:mFberT6ZtcchrsDtfvJM7aAH2bDKLdOnruUHl0hlapI= diff --git a/workflow_hugo.yaml b/workflow_hugo.yaml deleted file mode 100644 index eb6c933..0000000 --- a/workflow_hugo.yaml +++ /dev/null @@ -1,76 +0,0 @@ -# Sample workflow for building and deploying a Hugo site to GitHub Pages -name: Deploy Hugo site to Pages - -on: -# Runs on pushes targeting the default branch -push: - branches: - - main - -# Allows you to run this workflow manually from the Actions tab -workflow_dispatch: - -# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages -permissions: -contents: read -pages: write -id-token: write - -# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. -# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. -concurrency: -group: "pages" -cancel-in-progress: false - -# Default to bash -defaults: -run: - shell: bash - -jobs: -# Build job -build: - runs-on: ubuntu-latest - env: - HUGO_VERSION: 0.118.2 - steps: - - name: Install Hugo CLI - run: | - wget -O ${{ runner.temp }}/hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \ - && sudo dpkg -i ${{ runner.temp }}/hugo.deb - - name: Checkout - uses: actions/checkout@v4 - with: - submodules: recursive - fetch-depth: 0 - - name: Setup Pages - id: pages - uses: actions/configure-pages@v3 - - name: Install Node.js dependencies - run: "[[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true" - - name: Build with Hugo - env: - # For maximum backward compatibility with Hugo modules - HUGO_ENVIRONMENT: production - HUGO_ENV: production - run: | - hugo \ - --gc \ - --minify \ - --baseURL "${{ steps.pages.outputs.base_url }}/" - - name: Upload artifact - uses: actions/upload-pages-artifact@v1 - with: - path: ./public - -# Deployment job -deploy: - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - runs-on: ubuntu-latest - needs: build - steps: - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v2 \ No newline at end of file From 610c3513eae8710698cb79b014b1f7b4bada4046 Mon Sep 17 00:00:00 2001 From: luizacbcampos Date: Tue, 7 May 2024 21:38:35 -0300 Subject: [PATCH 23/43] fix docs --- data/landing.yaml | 2 +- hugo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/data/landing.yaml b/data/landing.yaml index be2fe75..09743a8 100644 --- a/data/landing.yaml +++ b/data/landing.yaml @@ -37,7 +37,7 @@ hero: cta2Button: icon: library_books btnText: "Documentação" - url: "/docs" + url: "/Biblioteca/docs/" info: "**Open Source** MIT Licensed." diff --git a/hugo.toml b/hugo.toml index c3d2646..430ff38 100644 --- a/hugo.toml +++ b/hugo.toml @@ -143,7 +143,7 @@ defaultContentLanguage = 'pt' [[menu.primary]] name = "Docs" - url = "/docs/" + url = "/docs/" identifier = "docs" weight = 10 From 4f6a7f3c767dde5b4ff8527d0d0922e8f326c57c Mon Sep 17 00:00:00 2001 From: Luiza Campos Date: Tue, 7 May 2024 21:44:17 -0300 Subject: [PATCH 24/43] Update hugo.yml --- .github/workflows/hugo.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/hugo.yml b/.github/workflows/hugo.yml index 73b2d3b..1ff76ac 100644 --- a/.github/workflows/hugo.yml +++ b/.github/workflows/hugo.yml @@ -45,7 +45,11 @@ jobs: hugo mod get - name: Build site with Hugo - run: hugo --minify --baseURL "${{ steps.pages.outputs.base_url }}/" + env: + # For maximum backward compatibility with Hugo modules + HUGO_ENVIRONMENT: production + HUGO_ENV: production + run: hugo --gc --minify --baseURL "${{ steps.pages.outputs.base_url }}/" - name: Upload artifact uses: actions/upload-pages-artifact@v3 From 9a133fc2fab3b1088e875ceb9ee6cb3a41564cdd Mon Sep 17 00:00:00 2001 From: Luiza Campos Date: Thu, 9 May 2024 10:55:08 -0300 Subject: [PATCH 25/43] Update hugo.yml trying to fix baseURL mistake --- .github/workflows/hugo.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/hugo.yml b/.github/workflows/hugo.yml index 1ff76ac..09c29bf 100644 --- a/.github/workflows/hugo.yml +++ b/.github/workflows/hugo.yml @@ -43,13 +43,17 @@ jobs: - name: Get Hugo modules run: | hugo mod get - + - name: Get baseURL from hugo.toml + id: get_base_url + run: | + echo "::set-output name=url::$(grep -Po '(?<=^baseURL = ")[^"]*' hugo.toml)" + - name: Build site with Hugo env: # For maximum backward compatibility with Hugo modules HUGO_ENVIRONMENT: production HUGO_ENV: production - run: hugo --gc --minify --baseURL "${{ steps.pages.outputs.base_url }}/" + run: hugo --gc --minify --baseURL "${{ steps.get_base_url.outputs.url }}/" - name: Upload artifact uses: actions/upload-pages-artifact@v3 From fe9002ef16da2524b078a2d0e06736714a511b5c Mon Sep 17 00:00:00 2001 From: Luiza Campos Date: Thu, 9 May 2024 10:59:04 -0300 Subject: [PATCH 26/43] Update hugo.yml remove deprecation warning --- .github/workflows/hugo.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/hugo.yml b/.github/workflows/hugo.yml index 09c29bf..4813d20 100644 --- a/.github/workflows/hugo.yml +++ b/.github/workflows/hugo.yml @@ -43,17 +43,19 @@ jobs: - name: Get Hugo modules run: | hugo mod get + - name: Get baseURL from hugo.toml id: get_base_url run: | - echo "::set-output name=url::$(grep -Po '(?<=^baseURL = ")[^"]*' hugo.toml)" + echo "HUGO_BASE_URL=$(grep -Po '(?<=^baseURL = ")[^"]*' hugo.toml)" >> $GITHUB_ENV - name: Build site with Hugo env: # For maximum backward compatibility with Hugo modules HUGO_ENVIRONMENT: production HUGO_ENV: production - run: hugo --gc --minify --baseURL "${{ steps.get_base_url.outputs.url }}/" + HUGO_BASE_URL: ${{ env.HUGO_BASE_URL }} + run: hugo --gc --minify --baseURL "${{ env.HUGO_BASE_URL }}/" - name: Upload artifact uses: actions/upload-pages-artifact@v3 From c5e34ec94de7773efb1158c42d16e890a4368a39 Mon Sep 17 00:00:00 2001 From: luizacbcampos Date: Thu, 9 May 2024 11:04:29 -0300 Subject: [PATCH 27/43] minor fixes --- .github/workflows/{hugo.yml => github_page.yml} | 0 hugo.toml | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename .github/workflows/{hugo.yml => github_page.yml} (100%) diff --git a/.github/workflows/hugo.yml b/.github/workflows/github_page.yml similarity index 100% rename from .github/workflows/hugo.yml rename to .github/workflows/github_page.yml diff --git a/hugo.toml b/hugo.toml index 430ff38..5869432 100644 --- a/hugo.toml +++ b/hugo.toml @@ -7,7 +7,7 @@ enableEmoji = true defaultContentLanguage = 'pt' [languages] [languages.pt] - title = "Lotus Docs Example Site" + title = "Biblioteca Maratona UFMG" languageName = "Português" weight = 10 # [languages.fr] From 72b63503912bfac4c6f040c1dedbffb8efc51b30 Mon Sep 17 00:00:00 2001 From: luizacbcampos Date: Thu, 9 May 2024 12:12:07 -0300 Subject: [PATCH 28/43] change logo --- assets/images/balloon.png | Bin 0 -> 5035 bytes data/landing.yaml | 10 +++++----- hugo.toml | 2 ++ 3 files changed, 7 insertions(+), 5 deletions(-) create mode 100644 assets/images/balloon.png diff --git a/assets/images/balloon.png b/assets/images/balloon.png new file mode 100644 index 0000000000000000000000000000000000000000..8755deb08c51c5a215105fc2f40500c16adbfe39 GIT binary patch literal 5035 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 BR}}yN literal 0 HcmV?d00001 diff --git a/data/landing.yaml b/data/landing.yaml index 09743a8..42c79d0 100644 --- a/data/landing.yaml +++ b/data/landing.yaml @@ -15,11 +15,11 @@ hero: desktop: "gradient-desktop.webp" mobile: "gradient-mobile.webp" - # titleLogo: - # path: "images/logos" - # filename: "title_logo.png" - # alt: "Lotus Docs Logo" - # height: 80px + titleLogo: + path: "images/" + filename: "balloon.png" + alt: "Balloon Logo - Balloon icons created by Stockio - Flaticon" + height: 80px image: diff --git a/hugo.toml b/hugo.toml index 5869432..6bfe212 100644 --- a/hugo.toml +++ b/hugo.toml @@ -158,3 +158,5 @@ defaultContentLanguage = 'pt' # url = "https://github.com/colinwilson/lotusdocs/discussions" # identifier = "community" # weight = 30 + + From 2bf77b94e8db54f75364bf9b48be0d67c3c09c12 Mon Sep 17 00:00:00 2001 From: luizacbcampos Date: Thu, 9 May 2024 12:14:49 -0300 Subject: [PATCH 29/43] attempt to change favicon --- static/android-chrome-192x192.png | Bin 0 -> 10244 bytes static/android-chrome-512x512.png | Bin 0 -> 21733 bytes static/apple-touch-icon.png | Bin 0 -> 5035 bytes static/favicon-16x16.png | Bin 0 -> 907 bytes static/favicon-32x32.png | Bin 0 -> 1593 bytes static/favicon.ico | Bin 0 -> 67646 bytes static/favicon.svg | 17 +++++++++++++++++ 7 files changed, 17 insertions(+) create mode 100644 static/android-chrome-192x192.png create mode 100644 static/android-chrome-512x512.png create mode 100644 static/apple-touch-icon.png create mode 100644 static/favicon-16x16.png create mode 100644 static/favicon-32x32.png create mode 100644 static/favicon.ico create mode 100644 static/favicon.svg diff --git a/static/android-chrome-192x192.png b/static/android-chrome-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..02b58a44a4c313950a0558fabc65b05f6949a9f0 GIT binary patch literal 10244 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 literal 0 HcmV?d00001 diff --git a/static/android-chrome-512x512.png b/static/android-chrome-512x512.png new file mode 100644 index 0000000000000000000000000000000000000000..33858f45ad302bc0ced35233c8951f3c95903e8b GIT binary patch literal 21733 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 KzR1|&!G8fc>d>(O literal 0 HcmV?d00001 diff --git a/static/apple-touch-icon.png b/static/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8755deb08c51c5a215105fc2f40500c16adbfe39 GIT binary patch literal 5035 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 BR}}yN literal 0 HcmV?d00001 diff --git a/static/favicon-16x16.png b/static/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..66b1855bedd9163f1bc94ae2d31608a8237b911c GIT binary patch literal 907 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!Lb6AYF9SoB8UsT^3j@P1pisjL z28L1t28LG&3=CE?7#PG0=IjczVPIfX2=EDU1u9UImlu_l?KLuJ($`a#msgRO*Hcu~ zRa8`#ll%YwzoMMHqP)D4tgO1cyrzPJhP*t#j10ewtO8I_K>?^YKwT|gN4r2r+gD9Z zK@OxH$Su;<1{%d6E)k)j9;Tr#EF)8)rvo%!P)0^vR<=S{r(RzdXeqa}bgZUEjHZUE zk`fS!$;t+(sR0d?my-)tR|`^Cla`ayR!{&M1+)l=fDGc%L?eSX1N}2LRu^oodJPRO z+FHGIwEO7naMjMbQD5)2z0F4_`*%+E@15-TTUoquvcGO;JDiO zf!<$Hx%e+Ij66$%{6OK030x0+|9;Tb`Qbxnp5423U%%Eh`S8J5^7{484uvykEY6?T zzRnamgO$5oh@(>?sGQlPOC-;OkH}&M2EHR8%s5q> zPZ}u5UgGKN%Kn0tlb=O%-O85_fI?e6T^vIsE{C286*}Y~z;eNrt^EPtLD{C=yMMEt z|J%=)7#uQV{mby!UV%v-sb;$mzbrbvwBbjvhV8whMO(l941J}~ARCdhZTDYAkI8H; zhmK#COg0k|RS?@BV|eVkOHf0|uVZyw?LJ-%zTf^O+&pf(e4@Ywqo2=Tf7LOtVya>e z)hUeG=^-iF5#kfFG-_=?n$bb-E3bOh{ut@6Epwk@f8p&{*91lh9(Sb+2P=&J&Yy9X zan1ezyq7LWc3Ak`JPh=JYKdz^NlIc#s#S7PDv)9@GB7gHH89mRunaLYwK6cVGB(vV zFt9Q(c(!59SriSq`6-!cmAExbe=AZ5)Sv;kp(HamwYVfPw*XU*i6O)iyCR7tKs}Nm uJ;C{DCFO}lsSM@i<$9TU*~Q6;1*v-ZMd`EO*+>BuF?hQAxvX literal 0 HcmV?d00001 diff --git a/static/favicon-32x32.png b/static/favicon-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..342c321b47282f952ecfefb1f08bd1b27ef70336 GIT binary patch literal 1593 zcma)52~ZPf6kfn^2DGiB$aZ%Va*zbVCL5B?K?312qZ|qp&{l(xC@PnUQgDiB8Kz*Z z*4Bg4Oi`*9RDz}>AX5ZE9C1p-8JBwSS;?YRArW=l$=0$M?Pe{cm^6 z;$x#d-RHYQ5ag*_5U~X8n0>iA0UhyWd8ge;U$7(wf(khhR9pf<;~-RgAA&aE5cIPi zf)x88Xm0N3rxvRq$Z<{lqQpo5U||>&LHtnE4`>)>+6|P2ASi;cP?QD33>1Z#Og0R& ze0`Z1<_GXF%mzUi=CIjp31#ko)Ia3C3K|u^bgbW4{V1u$C3uHPD0DwUHF#!go zfCdqu129a0VIU=AGNnwAL4g5W3_(Q<1`q~6AR$7Wk3;zwG|NVuk5NrLg_1qkkhhCB#UKh$d46l76Qpq9n@DNH@0)oc<5HpyjC zZ1#1vYFMjjAf*>nas!{28z7)micTe2CkwtC8ZxBSY!e0bX;i%$)e4?}yMp{7R9z(z zcdHalq;zYLuthFAuax(PhWw({>=fZ;cu=!kc3Lh==kxXwBL38HoK0ToijqJZ4l5T%M|5ZPRNH?Bx7-D(CJ6HCurG(*0xw?>bTR8< zB3p0yw?8h_FQRLb|@#F^Xf%bJOuMGkHF#c}DLjXGv>UX8_mQbM@Bc z>sOBXTRSecl^rUsNKHL>xWT&lOo#51!;in>6Q=!LHvC9UoJIOxCzWa&q$-qIwWae3 zqTDgt7;~(^GCFtB+l{M72F{xHuFfPzt8P?PH=A#qICvqMN~Jps#?0|C`m3^(D=mfH zOFwu#(DZ;lc6s(ZAM5S2?tg*D!@=9OeSbojI}_H*Mb3Lo#+sm@Z~C9H#jk=F{w z&533@QHgug=uC<_p10~^$612dhU;A@w=&&%UJXTWgb2d4w9vV5O?c9-irtp>52GDs znzEPAQqw5vDXorra<9T;TX~*fmOf3$3v5SRnSI;&_rkFF*%mzjJdIQ)XF)o$_;=zHq zJW&*^zzIb#F2HdGj_*`{{OL=CtelKYW5ItD`i(q)K=A+j1aoGV!DLR$%KbM-qQJ@N zLxQRjwgZljos*DbH0P(SH$eIM`NGWXwWjp6T!S!Y{i@1`s`&r}=^|qz>a_Z;e*)^g B`w;*D literal 0 HcmV?d00001 diff --git a/static/favicon.ico b/static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..5e662b50857d2e48da7f34c3eec86e7f72261416 GIT binary patch literal 67646 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 + + + + + + + From 773e7c89afa0e66d6e343ae283b27c349523279d Mon Sep 17 00:00:00 2001 From: luizacbcampos Date: Thu, 9 May 2024 13:11:40 -0300 Subject: [PATCH 30/43] attempt to replace logo --- static/images/logos/mark.svg | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 static/images/logos/mark.svg diff --git a/static/images/logos/mark.svg b/static/images/logos/mark.svg new file mode 100644 index 0000000..9647500 --- /dev/null +++ b/static/images/logos/mark.svg @@ -0,0 +1,17 @@ + + + + + + + + From 079989cb01e0a172dd43376a8ae9f20477d1bc52 Mon Sep 17 00:00:00 2001 From: luizacbcampos Date: Thu, 9 May 2024 13:16:59 -0300 Subject: [PATCH 31/43] fix svg with color --- static/favicon.svg | 168 +++++++++++++++++++++++++++++++---- static/images/logos/mark.svg | 168 +++++++++++++++++++++++++++++++---- 2 files changed, 302 insertions(+), 34 deletions(-) diff --git a/static/favicon.svg b/static/favicon.svg index 9647500..1f43c04 100644 --- a/static/favicon.svg +++ b/static/favicon.svg @@ -1,17 +1,151 @@ - - - - - - - - + + + + + + + + \ No newline at end of file diff --git a/static/images/logos/mark.svg b/static/images/logos/mark.svg index 9647500..1f43c04 100644 --- a/static/images/logos/mark.svg +++ b/static/images/logos/mark.svg @@ -1,17 +1,151 @@ - - - - - - - - + + + + + + + + \ No newline at end of file From 704370000b1c70dccf3687c43a66538a20ea8d24 Mon Sep 17 00:00:00 2001 From: luizacbcampos Date: Thu, 9 May 2024 13:20:20 -0300 Subject: [PATCH 32/43] fix logo background color --- static/favicon.svg | 159 ++--------------------------------- static/images/logos/mark.svg | 159 ++--------------------------------- 2 files changed, 16 insertions(+), 302 deletions(-) diff --git a/static/favicon.svg b/static/favicon.svg index 1f43c04..74373c7 100644 --- a/static/favicon.svg +++ b/static/favicon.svg @@ -1,151 +1,8 @@ - - - - - - - - \ No newline at end of file + + + + + + + + diff --git a/static/images/logos/mark.svg b/static/images/logos/mark.svg index 1f43c04..74373c7 100644 --- a/static/images/logos/mark.svg +++ b/static/images/logos/mark.svg @@ -1,151 +1,8 @@ - - - - - - - - \ No newline at end of file + + + + + + + + From 419bbf34243bc7047e0a040cb62d261e537f61fb Mon Sep 17 00:00:00 2001 From: luizacbcampos Date: Thu, 9 May 2024 13:24:33 -0300 Subject: [PATCH 33/43] svgs --- static/images/logos/logo.svg | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 static/images/logos/logo.svg diff --git a/static/images/logos/logo.svg b/static/images/logos/logo.svg new file mode 100644 index 0000000..74373c7 --- /dev/null +++ b/static/images/logos/logo.svg @@ -0,0 +1,8 @@ + + + + + + + + From 71078c23c8922204b293c43bcae08ed894b0ae17 Mon Sep 17 00:00:00 2001 From: luizacbcampos Date: Thu, 9 May 2024 13:31:03 -0300 Subject: [PATCH 34/43] move to correct folders --- assets/images/logos/logo.png | Bin 0 -> 5035 bytes {static => assets}/images/logos/logo.svg | 0 {static => assets}/images/logos/mark.svg | 0 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 assets/images/logos/logo.png rename {static => assets}/images/logos/logo.svg (100%) rename {static => assets}/images/logos/mark.svg (100%) diff --git a/assets/images/logos/logo.png b/assets/images/logos/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..8755deb08c51c5a215105fc2f40500c16adbfe39 GIT binary patch literal 5035 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 BR}}yN literal 0 HcmV?d00001 diff --git a/static/images/logos/logo.svg b/assets/images/logos/logo.svg similarity index 100% rename from static/images/logos/logo.svg rename to assets/images/logos/logo.svg diff --git a/static/images/logos/mark.svg b/assets/images/logos/mark.svg similarity index 100% rename from static/images/logos/mark.svg rename to assets/images/logos/mark.svg From 4c955b74c6c05be08dd55543808c0dd6a0ae9d60 Mon Sep 17 00:00:00 2001 From: luizacbcampos Date: Thu, 9 May 2024 13:36:46 -0300 Subject: [PATCH 35/43] fix size --- assets/images/logos/logo.svg | 2 +- assets/images/logos/mark.svg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/images/logos/logo.svg b/assets/images/logos/logo.svg index 74373c7..63966bf 100644 --- a/assets/images/logos/logo.svg +++ b/assets/images/logos/logo.svg @@ -1,6 +1,6 @@ - + diff --git a/assets/images/logos/mark.svg b/assets/images/logos/mark.svg index 74373c7..63966bf 100644 --- a/assets/images/logos/mark.svg +++ b/assets/images/logos/mark.svg @@ -1,6 +1,6 @@ - + From 5697e97380ef3ff549a8ec3a8757204753f674d2 Mon Sep 17 00:00:00 2001 From: luizacbcampos Date: Thu, 9 May 2024 13:40:16 -0300 Subject: [PATCH 36/43] logo fix new --- assets/images/logos/logo.svg | 3 +-- assets/images/logos/mark.svg | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/assets/images/logos/logo.svg b/assets/images/logos/logo.svg index 63966bf..64f1751 100644 --- a/assets/images/logos/logo.svg +++ b/assets/images/logos/logo.svg @@ -1,6 +1,5 @@ - - + diff --git a/assets/images/logos/mark.svg b/assets/images/logos/mark.svg index 63966bf..64f1751 100644 --- a/assets/images/logos/mark.svg +++ b/assets/images/logos/mark.svg @@ -1,6 +1,5 @@ - - + From 5d7bebd589f6c37bcf3c58b2db19f8d38491df9c Mon Sep 17 00:00:00 2001 From: luizacbcampos Date: Thu, 9 May 2024 13:43:04 -0300 Subject: [PATCH 37/43] remove viewbox from svg files --- assets/images/logos/logo.svg | 2 +- assets/images/logos/mark.svg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/images/logos/logo.svg b/assets/images/logos/logo.svg index 64f1751..33ff1b9 100644 --- a/assets/images/logos/logo.svg +++ b/assets/images/logos/logo.svg @@ -1,5 +1,5 @@ - + diff --git a/assets/images/logos/mark.svg b/assets/images/logos/mark.svg index 64f1751..33ff1b9 100644 --- a/assets/images/logos/mark.svg +++ b/assets/images/logos/mark.svg @@ -1,5 +1,5 @@ - + From ad8d724cb0a2c0569519f04dc1d3cc496fe30416 Mon Sep 17 00:00:00 2001 From: luizacbcampos Date: Thu, 9 May 2024 17:18:55 -0300 Subject: [PATCH 38/43] fixes the viewbox option --- assets/images/logos/logo.svg | 2 +- assets/images/logos/mark.svg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/images/logos/logo.svg b/assets/images/logos/logo.svg index 33ff1b9..e03ecc1 100644 --- a/assets/images/logos/logo.svg +++ b/assets/images/logos/logo.svg @@ -1,5 +1,5 @@ - + diff --git a/assets/images/logos/mark.svg b/assets/images/logos/mark.svg index 33ff1b9..e03ecc1 100644 --- a/assets/images/logos/mark.svg +++ b/assets/images/logos/mark.svg @@ -1,5 +1,5 @@ - + From a405173f340fb54cf2516db13fd4d8aa01ebddb8 Mon Sep 17 00:00:00 2001 From: luizacbcampos Date: Thu, 9 May 2024 17:23:06 -0300 Subject: [PATCH 39/43] adding algos --- content/docs/DP/_index.md | 8 + content/docs/DP/dcDp.md | 45 +++ content/docs/DP/lcs.md | 94 +++++ content/docs/DP/mochila.md | 54 +++ content/docs/DP/sosDP.md | 40 ++ content/docs/DP/subsetSum.md | 44 +++ content/docs/Estruturas/_index.md | 8 + content/docs/Estruturas/bit.md | 66 ++++ content/docs/Estruturas/bit2d.md | 69 ++++ content/docs/Estruturas/bitRange.md | 62 +++ content/docs/Estruturas/bitSortTree.md | 62 +++ content/docs/Estruturas/cht.md | 57 +++ content/docs/Estruturas/chtDinamico.md | 73 ++++ content/docs/Estruturas/dsu.md | 141 +++++++ content/docs/Estruturas/lichao.md | 68 ++++ content/docs/Estruturas/lichaoLazy.md | 115 ++++++ content/docs/Estruturas/mergeSortTree.md | 148 +++++++ content/docs/Estruturas/minqueueDeque.md | 35 ++ content/docs/Estruturas/minqueueStack.md | 57 +++ content/docs/Estruturas/orderStatisticSet.md | 44 +++ content/docs/Estruturas/priorityQueueDs.md | 96 +++++ content/docs/Estruturas/rangeColor.md | 60 +++ content/docs/Estruturas/rmq.md | 52 +++ content/docs/Estruturas/slopeTrick.md | 150 +++++++ content/docs/Estruturas/sparseTable.md | 43 ++ .../docs/Estruturas/sparseTableDisjunta.md | 52 +++ content/docs/Estruturas/splaytree.md | 143 +++++++ content/docs/Estruturas/splaytreeImplicita.md | 195 +++++++++ content/docs/Estruturas/splitMergeSet.md | 196 ++++++++++ content/docs/Estruturas/splitMergeSetLazy.md | 240 ++++++++++++ content/docs/Estruturas/sqrtTree.md | 68 ++++ content/docs/Estruturas/treap.md | 131 +++++++ content/docs/Estruturas/treapImplicita.md | 107 +++++ content/docs/Estruturas/treapPersistent.md | 72 ++++ content/docs/Estruturas/waveletTree.md | 95 +++++ content/docs/Extra/_index.md | 8 + content/docs/Grafos/_index.md | 8 + content/docs/Grafos/articulationPoints.md | 64 +++ content/docs/Grafos/bellmanFord.md | 54 +++ content/docs/Grafos/blockCutTree.md | 116 ++++++ content/docs/Grafos/blossom.md | 105 +++++ content/docs/Grafos/center.md | 51 +++ content/docs/Grafos/centroid.md | 48 +++ content/docs/Grafos/centroidDecomp.md | 66 ++++ content/docs/Grafos/centroidTree.md | 63 +++ content/docs/Grafos/cover.md | 77 ++++ content/docs/Grafos/dijkstra.md | 51 +++ content/docs/Grafos/dinitz.md | 92 +++++ content/docs/Grafos/directedMst.md | 91 +++++ content/docs/Grafos/dominatorTree.md | 107 +++++ content/docs/Grafos/eulerPath.md | 98 +++++ content/docs/Grafos/eulerTourTree.md | 211 ++++++++++ content/docs/Grafos/floydWarshall.md | 48 +++ content/docs/Grafos/functionalGraph.md | 134 +++++++ content/docs/Grafos/hopcroftKarp.md | 89 +++++ content/docs/Grafos/johnson.md | 65 +++ content/docs/Grafos/kosaraju.md | 53 +++ content/docs/Grafos/kruskal.md | 48 +++ content/docs/Grafos/kuhn.md | 86 ++++ content/docs/Grafos/linetree.md | 71 ++++ content/docs/Grafos/lowerBoundMaxFlow.md | 66 ++++ content/docs/Grafos/minCostMaxFlow.md | 149 +++++++ content/docs/Grafos/prufer.md | 73 ++++ content/docs/Grafos/sack.md | 53 +++ content/docs/Grafos/stableMarriage.md | 68 ++++ content/docs/Grafos/tarjan.md | 53 +++ content/docs/Grafos/topoSort.md | 46 +++ content/docs/Grafos/treeIsomorf.md | 129 ++++++ content/docs/Grafos/virtualTree.md | 59 +++ content/docs/Matematica/2sat.md | 91 +++++ content/docs/Matematica/_index.md | 8 + content/docs/Matematica/berlekampMassey.md | 110 ++++++ content/docs/Matematica/chinese.md | 46 +++ content/docs/Matematica/convolution.md | 135 +++++++ content/docs/Matematica/coprimeBasis.md | 77 ++++ content/docs/Matematica/crivo.md | 171 ++++++++ content/docs/Matematica/cycleDetection.md | 51 +++ content/docs/Matematica/diofantina.md | 68 ++++ content/docs/Matematica/divisionTrick.md | 26 ++ content/docs/Matematica/evalInterpol.md | 50 +++ content/docs/Matematica/fastPow.md | 35 ++ content/docs/Matematica/fwht.md | 96 +++++ content/docs/Matematica/gauss.md | 67 ++++ content/docs/Matematica/gaussZ2.md | 72 ++++ content/docs/Matematica/gcdEstendido.md | 31 ++ content/docs/Matematica/gcdLcmConvolution.md | 54 +++ content/docs/Matematica/integral.md | 28 ++ content/docs/Matematica/karatsuba.md | 61 +++ content/docs/Matematica/logDiscreto.md | 61 +++ content/docs/Matematica/millerRabin.md | 57 +++ content/docs/Matematica/modInverse.md | 32 ++ content/docs/Matematica/mulmod.md | 24 ++ .../docs/Matematica/multipointEvaluation.md | 86 ++++ content/docs/Matematica/ntt.md | 64 +++ content/docs/Matematica/pollardrho.md | 89 +++++ content/docs/Matematica/powerSeries.md | 128 ++++++ .../docs/Matematica/probabilityBinomial.md | 32 ++ content/docs/Matematica/simplex.md | 82 ++++ content/docs/Matematica/totiente.md | 31 ++ content/docs/Primitivas/_index.md | 8 + content/docs/Primitivas/bigint.md | 278 +++++++++++++ content/docs/Primitivas/calendario.md | 41 ++ content/docs/Primitivas/frac.md | 50 +++ content/docs/Primitivas/geometria.md | 369 ++++++++++++++++++ content/docs/Primitivas/geometria3d.md | 188 +++++++++ content/docs/Primitivas/geometriaInt.md | 251 ++++++++++++ content/docs/Primitivas/matrix.md | 76 ++++ content/docs/Primitivas/matroid.md | 218 +++++++++++ content/docs/Primitivas/modularArithmetic.md | 88 +++++ content/docs/Problemas/_index.md | 8 + content/docs/Problemas/additionChain.md | 49 +++ content/docs/Problemas/angleRange.md | 61 +++ content/docs/Problemas/areaHistograma.md | 44 +++ content/docs/Problemas/areaUniaoRetangulo.md | 106 +++++ content/docs/Problemas/binomial.md | 100 +++++ content/docs/Problemas/closestPairOfPoints.md | 53 +++ .../docs/Problemas/conectividadeDinamica.md | 81 ++++ .../docs/Problemas/conectividadeDinamica2.md | 152 ++++++++ content/docs/Problemas/deBrujin.md | 53 +++ content/docs/Problemas/delaunay.md | 169 ++++++++ content/docs/Problemas/distinct.md | 45 +++ content/docs/Problemas/distinctUpdate.md | 113 ++++++ content/docs/Problemas/dominacao3d.md | 90 +++++ content/docs/Problemas/dominatorPoints.md | 84 ++++ content/docs/Problemas/dynamicHull.md | 62 +++ content/docs/Problemas/graphTriangles.md | 44 +++ content/docs/Problemas/grayCode.md | 31 ++ .../docs/Problemas/halfPlaneIntersection.md | 46 +++ content/docs/Problemas/heapSort.md | 33 ++ content/docs/Problemas/hungarian.md | 72 ++++ .../docs/Problemas/intervalGraphColoring.md | 48 +++ content/docs/Problemas/intervalGraphIndSet.md | 62 +++ content/docs/Problemas/inversionCount.md | 50 +++ content/docs/Problemas/lis.md | 46 +++ content/docs/Problemas/lis2.md | 34 ++ content/docs/Problemas/maxDist.md | 49 +++ content/docs/Problemas/minCirc.md | 67 ++++ content/docs/Problemas/minkowski.md | 55 +++ content/docs/Problemas/mo.md | 90 +++++ content/docs/Problemas/moDsu.md | 108 +++++ content/docs/Problemas/moOnTrees.md | 107 +++++ .../Problemas/palindromicFactorization.md | 54 +++ content/docs/Problemas/parsing.md | 103 +++++ content/docs/Problemas/rmqOffline.md | 45 +++ content/docs/Problemas/segmentIntersection.md | 61 +++ content/docs/Problemas/simplePolygon.md | 67 ++++ content/docs/Problemas/steinerTree.md | 110 ++++++ content/docs/Problemas/sweepDirection.md | 54 +++ content/docs/Strings/_index.md | 8 + content/docs/Strings/ahocorasick.md | 70 ++++ content/docs/Strings/dynamicSuffixArray.md | 212 ++++++++++ content/docs/Strings/eertree.md | 69 ++++ content/docs/Strings/hashing.md | 45 +++ content/docs/Strings/hashingLargeMod.md | 59 +++ content/docs/Strings/kmp.md | 67 ++++ content/docs/Strings/manacher.md | 77 ++++ content/docs/Strings/minMaxSuffixCyclic.md | 55 +++ content/docs/Strings/suffixArray.md | 211 ++++++++++ content/docs/Strings/suffixArray2.md | 64 +++ content/docs/Strings/suffixAutomaton.md | 83 ++++ content/docs/Strings/trie.md | 75 ++++ content/docs/Strings/z.md | 41 ++ 162 files changed, 12962 insertions(+) create mode 100644 content/docs/DP/_index.md create mode 100644 content/docs/DP/dcDp.md create mode 100644 content/docs/DP/lcs.md create mode 100644 content/docs/DP/mochila.md create mode 100644 content/docs/DP/sosDP.md create mode 100644 content/docs/DP/subsetSum.md create mode 100644 content/docs/Estruturas/_index.md create mode 100644 content/docs/Estruturas/bit.md create mode 100644 content/docs/Estruturas/bit2d.md create mode 100644 content/docs/Estruturas/bitRange.md create mode 100644 content/docs/Estruturas/bitSortTree.md create mode 100644 content/docs/Estruturas/cht.md create mode 100644 content/docs/Estruturas/chtDinamico.md create mode 100644 content/docs/Estruturas/dsu.md create mode 100644 content/docs/Estruturas/lichao.md create mode 100644 content/docs/Estruturas/lichaoLazy.md create mode 100644 content/docs/Estruturas/mergeSortTree.md create mode 100644 content/docs/Estruturas/minqueueDeque.md create mode 100644 content/docs/Estruturas/minqueueStack.md create mode 100644 content/docs/Estruturas/orderStatisticSet.md create mode 100644 content/docs/Estruturas/priorityQueueDs.md create mode 100644 content/docs/Estruturas/rangeColor.md create mode 100644 content/docs/Estruturas/rmq.md create mode 100644 content/docs/Estruturas/slopeTrick.md create mode 100644 content/docs/Estruturas/sparseTable.md create mode 100644 content/docs/Estruturas/sparseTableDisjunta.md create mode 100644 content/docs/Estruturas/splaytree.md create mode 100644 content/docs/Estruturas/splaytreeImplicita.md create mode 100644 content/docs/Estruturas/splitMergeSet.md create mode 100644 content/docs/Estruturas/splitMergeSetLazy.md create mode 100644 content/docs/Estruturas/sqrtTree.md create mode 100644 content/docs/Estruturas/treap.md create mode 100644 content/docs/Estruturas/treapImplicita.md create mode 100644 content/docs/Estruturas/treapPersistent.md create mode 100644 content/docs/Estruturas/waveletTree.md create mode 100644 content/docs/Extra/_index.md create mode 100644 content/docs/Grafos/_index.md create mode 100644 content/docs/Grafos/articulationPoints.md create mode 100644 content/docs/Grafos/bellmanFord.md create mode 100644 content/docs/Grafos/blockCutTree.md create mode 100644 content/docs/Grafos/blossom.md create mode 100644 content/docs/Grafos/center.md create mode 100644 content/docs/Grafos/centroid.md create mode 100644 content/docs/Grafos/centroidDecomp.md create mode 100644 content/docs/Grafos/centroidTree.md create mode 100644 content/docs/Grafos/cover.md create mode 100644 content/docs/Grafos/dijkstra.md create mode 100644 content/docs/Grafos/dinitz.md create mode 100644 content/docs/Grafos/directedMst.md create mode 100644 content/docs/Grafos/dominatorTree.md create mode 100644 content/docs/Grafos/eulerPath.md create mode 100644 content/docs/Grafos/eulerTourTree.md create mode 100644 content/docs/Grafos/floydWarshall.md create mode 100644 content/docs/Grafos/functionalGraph.md create mode 100644 content/docs/Grafos/hopcroftKarp.md create mode 100644 content/docs/Grafos/johnson.md create mode 100644 content/docs/Grafos/kosaraju.md create mode 100644 content/docs/Grafos/kruskal.md create mode 100644 content/docs/Grafos/kuhn.md create mode 100644 content/docs/Grafos/linetree.md create mode 100644 content/docs/Grafos/lowerBoundMaxFlow.md create mode 100644 content/docs/Grafos/minCostMaxFlow.md create mode 100644 content/docs/Grafos/prufer.md create mode 100644 content/docs/Grafos/sack.md create mode 100644 content/docs/Grafos/stableMarriage.md create mode 100644 content/docs/Grafos/tarjan.md create mode 100644 content/docs/Grafos/topoSort.md create mode 100644 content/docs/Grafos/treeIsomorf.md create mode 100644 content/docs/Grafos/virtualTree.md create mode 100644 content/docs/Matematica/2sat.md create mode 100644 content/docs/Matematica/_index.md create mode 100644 content/docs/Matematica/berlekampMassey.md create mode 100644 content/docs/Matematica/chinese.md create mode 100644 content/docs/Matematica/convolution.md create mode 100644 content/docs/Matematica/coprimeBasis.md create mode 100644 content/docs/Matematica/crivo.md create mode 100644 content/docs/Matematica/cycleDetection.md create mode 100644 content/docs/Matematica/diofantina.md create mode 100644 content/docs/Matematica/divisionTrick.md create mode 100644 content/docs/Matematica/evalInterpol.md create mode 100644 content/docs/Matematica/fastPow.md create mode 100644 content/docs/Matematica/fwht.md create mode 100644 content/docs/Matematica/gauss.md create mode 100644 content/docs/Matematica/gaussZ2.md create mode 100644 content/docs/Matematica/gcdEstendido.md create mode 100644 content/docs/Matematica/gcdLcmConvolution.md create mode 100644 content/docs/Matematica/integral.md create mode 100644 content/docs/Matematica/karatsuba.md create mode 100644 content/docs/Matematica/logDiscreto.md create mode 100644 content/docs/Matematica/millerRabin.md create mode 100644 content/docs/Matematica/modInverse.md create mode 100644 content/docs/Matematica/mulmod.md create mode 100644 content/docs/Matematica/multipointEvaluation.md create mode 100644 content/docs/Matematica/ntt.md create mode 100644 content/docs/Matematica/pollardrho.md create mode 100644 content/docs/Matematica/powerSeries.md create mode 100644 content/docs/Matematica/probabilityBinomial.md create mode 100644 content/docs/Matematica/simplex.md create mode 100644 content/docs/Matematica/totiente.md create mode 100644 content/docs/Primitivas/_index.md create mode 100644 content/docs/Primitivas/bigint.md create mode 100644 content/docs/Primitivas/calendario.md create mode 100644 content/docs/Primitivas/frac.md create mode 100644 content/docs/Primitivas/geometria.md create mode 100644 content/docs/Primitivas/geometria3d.md create mode 100644 content/docs/Primitivas/geometriaInt.md create mode 100644 content/docs/Primitivas/matrix.md create mode 100644 content/docs/Primitivas/matroid.md create mode 100644 content/docs/Primitivas/modularArithmetic.md create mode 100644 content/docs/Problemas/_index.md create mode 100644 content/docs/Problemas/additionChain.md create mode 100644 content/docs/Problemas/angleRange.md create mode 100644 content/docs/Problemas/areaHistograma.md create mode 100644 content/docs/Problemas/areaUniaoRetangulo.md create mode 100644 content/docs/Problemas/binomial.md create mode 100644 content/docs/Problemas/closestPairOfPoints.md create mode 100644 content/docs/Problemas/conectividadeDinamica.md create mode 100644 content/docs/Problemas/conectividadeDinamica2.md create mode 100644 content/docs/Problemas/deBrujin.md create mode 100644 content/docs/Problemas/delaunay.md create mode 100644 content/docs/Problemas/distinct.md create mode 100644 content/docs/Problemas/distinctUpdate.md create mode 100644 content/docs/Problemas/dominacao3d.md create mode 100644 content/docs/Problemas/dominatorPoints.md create mode 100644 content/docs/Problemas/dynamicHull.md create mode 100644 content/docs/Problemas/graphTriangles.md create mode 100644 content/docs/Problemas/grayCode.md create mode 100644 content/docs/Problemas/halfPlaneIntersection.md create mode 100644 content/docs/Problemas/heapSort.md create mode 100644 content/docs/Problemas/hungarian.md create mode 100644 content/docs/Problemas/intervalGraphColoring.md create mode 100644 content/docs/Problemas/intervalGraphIndSet.md create mode 100644 content/docs/Problemas/inversionCount.md create mode 100644 content/docs/Problemas/lis.md create mode 100644 content/docs/Problemas/lis2.md create mode 100644 content/docs/Problemas/maxDist.md create mode 100644 content/docs/Problemas/minCirc.md create mode 100644 content/docs/Problemas/minkowski.md create mode 100644 content/docs/Problemas/mo.md create mode 100644 content/docs/Problemas/moDsu.md create mode 100644 content/docs/Problemas/moOnTrees.md create mode 100644 content/docs/Problemas/palindromicFactorization.md create mode 100644 content/docs/Problemas/parsing.md create mode 100644 content/docs/Problemas/rmqOffline.md create mode 100644 content/docs/Problemas/segmentIntersection.md create mode 100644 content/docs/Problemas/simplePolygon.md create mode 100644 content/docs/Problemas/steinerTree.md create mode 100644 content/docs/Problemas/sweepDirection.md create mode 100644 content/docs/Strings/_index.md create mode 100644 content/docs/Strings/ahocorasick.md create mode 100644 content/docs/Strings/dynamicSuffixArray.md create mode 100644 content/docs/Strings/eertree.md create mode 100644 content/docs/Strings/hashing.md create mode 100644 content/docs/Strings/hashingLargeMod.md create mode 100644 content/docs/Strings/kmp.md create mode 100644 content/docs/Strings/manacher.md create mode 100644 content/docs/Strings/minMaxSuffixCyclic.md create mode 100644 content/docs/Strings/suffixArray.md create mode 100644 content/docs/Strings/suffixArray2.md create mode 100644 content/docs/Strings/suffixAutomaton.md create mode 100644 content/docs/Strings/trie.md create mode 100644 content/docs/Strings/z.md diff --git a/content/docs/DP/_index.md b/content/docs/DP/_index.md new file mode 100644 index 0000000..5e92923 --- /dev/null +++ b/content/docs/DP/_index.md @@ -0,0 +1,8 @@ +--- +weight: 10 +title: "DP" +draft: false +date: "2024-05-09T17:19:25-0300" +description: "" +publishdate: "2024-05-09T17:19:25-0300" +--- diff --git a/content/docs/DP/dcDp.md b/content/docs/DP/dcDp.md new file mode 100644 index 0000000..5ef3b32 --- /dev/null +++ b/content/docs/DP/dcDp.md @@ -0,0 +1,45 @@ +--- +weight: 10 +title: "Divide and Conquer DP" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Particiona o array em k subarrays + + minimizando o somatorio das queries + + + + O(k n log n), assumindo quer query(l, r) eh O(1) + + + +Link original: [dcDp.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/DP/dcDp.cpp) + +## Código +```cpp +ll dp[MAX][2]; + +void solve(int k, int l, int r, int lk, int rk) { + if (l > r) return; + int m = (l+r)/2, p = -1; + auto& ans = dp[m][k&1] = LINF; + for (int i = max(m, lk); i <= rk; i++) { + ll at = dp[i+1][~k&1] + query(m, i); + if (at < ans) ans = at, p = i; + } + solve(k, l, m-1, lk, p), solve(k, m+1, r, p, rk); +} + +ll DC(int n, int k) { + dp[n][0] = dp[n][1] = 0; + for (int i = 0; i < n; i++) dp[i][0] = LINF; + for (int i = 1; i <= k; i++) solve(i, 0, n-i, 0, n-i); + return dp[0][k&1]; +} +``` diff --git a/content/docs/DP/lcs.md b/content/docs/DP/lcs.md new file mode 100644 index 0000000..020590c --- /dev/null +++ b/content/docs/DP/lcs.md @@ -0,0 +1,94 @@ +--- +weight: 10 +title: "Longest Common Subsequence" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Computa a LCS entre dois arrays usando + + o algoritmo de Hirschberg para recuperar + + + + O(n*m), O(n+m) de memoria + + + +Link original: [lcs.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/DP/lcs.cpp) + +## Código +```cpp +int lcs_s[MAX], lcs_t[MAX]; +int dp[2][MAX]; + +// dp[0][j] = max lcs(s[li...ri], t[lj, lj+j]) +void dp_top(int li, int ri, int lj, int rj) { + memset(dp[0], 0, (rj-lj+1)*sizeof(dp[0][0])); + for (int i = li; i <= ri; i++) { + for (int j = rj; j >= lj; j--) + dp[0][j - lj] = max(dp[0][j - lj], + (lcs_s[i] == lcs_t[j]) + (j > lj ? dp[0][j-1 - lj] : 0)); + for (int j = lj+1; j <= rj; j++) + dp[0][j - lj] = max(dp[0][j - lj], dp[0][j-1 -lj]); + } +} + +// dp[1][j] = max lcs(s[li...ri], t[lj+j, rj]) +void dp_bottom(int li, int ri, int lj, int rj) { + memset(dp[1], 0, (rj-lj+1)*sizeof(dp[1][0])); + for (int i = ri; i >= li; i--) { + for (int j = lj; j <= rj; j++) + dp[1][j - lj] = max(dp[1][j - lj], + (lcs_s[i] == lcs_t[j]) + (j < rj ? dp[1][j+1 - lj] : 0)); + for (int j = rj-1; j >= lj; j--) + dp[1][j - lj] = max(dp[1][j - lj], dp[1][j+1 - lj]); + } +} + +void solve(vector& ans, int li, int ri, int lj, int rj) { + if (li == ri){ + for (int j = lj; j <= rj; j++) + if (lcs_s[li] == lcs_t[j]){ + ans.push_back(lcs_t[j]); + break; + } + return; + } + if (lj == rj){ + for (int i = li; i <= ri; i++){ + if (lcs_s[i] == lcs_t[lj]){ + ans.push_back(lcs_s[i]); + break; + } + } + return; + } + int mi = (li+ri)/2; + dp_top(li, mi, lj, rj), dp_bottom(mi+1, ri, lj, rj); + + int j_ = 0, mx = -1; + + for (int j = lj-1; j <= rj; j++) { + int val = 0; + if (j >= lj) val += dp[0][j - lj]; + if (j < rj) val += dp[1][j+1 - lj]; + + if (val >= mx) mx = val, j_ = j; + } + if (mx == -1) return; + solve(ans, li, mi, lj, j_), solve(ans, mi+1, ri, j_+1, rj); +} + +vector lcs(const vector& s, const vector& t) { + for (int i = 0; i < s.size(); i++) lcs_s[i] = s[i]; + for (int i = 0; i < t.size(); i++) lcs_t[i] = t[i]; + vector ans; + solve(ans, 0, s.size()-1, 0, t.size()-1); + return ans; +} +``` diff --git a/content/docs/DP/mochila.md b/content/docs/DP/mochila.md new file mode 100644 index 0000000..2fd1cc1 --- /dev/null +++ b/content/docs/DP/mochila.md @@ -0,0 +1,54 @@ +--- +weight: 10 +title: "Mochila" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Resolve mochila, recuperando a resposta + + + + O(n * cap), O(n + cap) de memoria + + + +Link original: [mochila.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/DP/mochila.cpp) + +## Código +```cpp +int v[MAX], w[MAX]; // valor e peso +int dp[2][MAX_CAP]; + +// DP usando os itens [l, r], com capacidade = cap +void get_dp(int x, int l, int r, int cap) { + memset(dp[x], 0, (cap+1)*sizeof(dp[x][0])); + for (int i = l; i <= r; i++) for (int j = cap; j >= 0; j--) + if (j - w[i] >= 0) dp[x][j] = max(dp[x][j], v[i] + dp[x][j - w[i]]); +} + +void solve(vector& ans, int l, int r, int cap) { + if (l == r) { + if (w[l] <= cap) ans.push_back(l); + return; + } + int m = (l+r)/2; + get_dp(0, l, m, cap), get_dp(1, m+1, r, cap); + int left_cap = -1, opt = -INF; + for (int j = 0; j <= cap; j++) + if (int at = dp[0][j] + dp[1][cap - j]; at > opt) + opt = at, left_cap = j; + solve(ans, l, m, left_cap), solve(ans, m+1, r, cap - left_cap); +} + +vector knapsack(int n, int cap) { + vector ans; + solve(ans, 0, n-1, cap); + return ans; +} + +``` diff --git a/content/docs/DP/sosDP.md b/content/docs/DP/sosDP.md new file mode 100644 index 0000000..107bdc8 --- /dev/null +++ b/content/docs/DP/sosDP.md @@ -0,0 +1,40 @@ +--- +weight: 10 +title: "SOS DP" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + O(n 2^n) + + + + soma de sub-conjunto + +Link original: [sosDP.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/DP/sosDP.cpp) + +## Código +```cpp +vector sos_dp(vector f) { + int N = __builtin_ctz(f.size()); + assert((1<>i&1) f[mask] += f[mask^(1< sos_dp(vector f) { + int N = __builtin_ctz(f.size()); + assert((1<>i&1) f[mask] += f[mask^(1< w, int t) { + int pref = 0, k = 0; + while (k < w.size() and pref + w[k] <= t) pref += w[k++]; + if (k == w.size()) return pref; + int W = *max_element(w.begin(), w.end()); + vector last, dp(2*W, -1); + dp[W - (t-pref)] = k; + for (int i = k; i < w.size(); i++) { + last = dp; + for (int x = 0; x < W; x++) dp[x+w[i]] = max(dp[x+w[i]], last[x]); + for (int x = 2*W - 1; x > W; x--) + for (int j = max(0, last[x]); j < dp[x]; j++) + dp[x-w[j]] = max(dp[x-w[j]], j); + } + int ans = t; + while (dp[W - (t-ans)] < 0) ans--; + return ans; +} +``` diff --git a/content/docs/Estruturas/_index.md b/content/docs/Estruturas/_index.md new file mode 100644 index 0000000..7da7f37 --- /dev/null +++ b/content/docs/Estruturas/_index.md @@ -0,0 +1,8 @@ +--- +weight: 10 +title: "Estruturas" +draft: false +date: "2024-05-09T17:19:25-0300" +description: "" +publishdate: "2024-05-09T17:19:25-0300" +--- diff --git a/content/docs/Estruturas/bit.md b/content/docs/Estruturas/bit.md new file mode 100644 index 0000000..4f636be --- /dev/null +++ b/content/docs/Estruturas/bit.md @@ -0,0 +1,66 @@ +--- +weight: 10 +title: "BIT" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + BIT de soma 0-based + + + + upper_bound(x) retorna o menor p tal que pref(p) > x + + + + Complexidades: + + build - O(n) + + update - O(log(n)) + + query - O(log(n)) + + upper_bound - O(log(n)) + + + +Link original: [bit.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Estruturas/bit.cpp) + +## Código +```cpp +struct Bit { + int n; + vector bit; + Bit(int _n=0) : n(_n), bit(n + 1) {} + Bit(vector& v) : n(v.size()), bit(n + 1) { + for (int i = 1; i <= n; i++) { + bit[i] += v[i - 1]; + int j = i + (i & -i); + if (j <= n) bit[j] += bit[i]; + } + } + void update(int i, ll x) { // soma x na posicao i + for (i++; i <= n; i += i & -i) bit[i] += x; + } + ll pref(int i) { // soma [0, i] + ll ret = 0; + for (i++; i; i -= i & -i) ret += bit[i]; + return ret; + } + ll query(int l, int r) { // soma [l, r] + return pref(r) - pref(l - 1); + } + int upper_bound(ll x) { + int p = 0; + for (int i = __lg(n); i+1; i--) + if (p + (1< struct bit2d { + vector X; + vector> Y, t; + + int ub(vector& v, T x) { + return upper_bound(v.begin(), v.end(), x) - v.begin(); + } + bit2d(vector> v) { + for (auto [x, y] : v) X.push_back(x); + sort(X.begin(), X.end()); + X.erase(unique(X.begin(), X.end()), X.end()); + + t.resize(X.size() + 1); + Y.resize(t.size()); + sort(v.begin(), v.end(), [](auto a, auto b) { + return a.second < b.second; }); + for (auto [x, y] : v) for (int i = ub(X, x); i < t.size(); i += i&-i) + if (!Y[i].size() or Y[i].back() != y) Y[i].push_back(y); + + for (int i = 0; i < t.size(); i++) t[i].resize(Y[i].size() + 1); + } + + void update(T x, T y, T v) { + for (int i = ub(X, x); i < t.size(); i += i&-i) + for (int j = ub(Y[i], y); j < t[i].size(); j += j&-j) t[i][j] += v; + } + + T query(T x, T y) { + T ans = 0; + for (int i = ub(X, x); i; i -= i&-i) + for (int j = ub(Y[i], y); j; j -= j&-j) ans += t[i][j]; + return ans; + } + T query(T x1, T y1, T x2, T y2) { + return query(x2, y2)-query(x2, y1-1)-query(x1-1, y2)+query(x1-1, y1-1); + } +}; +``` diff --git a/content/docs/Estruturas/bitRange.md b/content/docs/Estruturas/bitRange.md new file mode 100644 index 0000000..b862129 --- /dev/null +++ b/content/docs/Estruturas/bitRange.md @@ -0,0 +1,62 @@ +--- +weight: 10 +title: "BIT com update em range" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Operacoes 0-based + + query(l, r) retorna a soma de v[l..r] + + update(l, r, x) soma x em v[l..r] + + + + Complexidades: + + build - O(n) + + query - O(log(n)) + + update - O(log(n)) + + + +Link original: [bitRange.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Estruturas/bitRange.cpp) + +## Código +```cpp +namespace bit { + ll bit[2][MAX+2]; + int n; + + void build(int n2, int* v) { + n = n2; + for (int i = 1; i <= n; i++) + bit[1][min(n+1, i+(i&-i))] += bit[1][i] += v[i-1]; + } + ll get(int x, int i) { + ll ret = 0; + for (; i; i -= i&-i) ret += bit[x][i]; + return ret; + } + void add(int x, int i, ll val) { + for (; i <= n; i += i&-i) bit[x][i] += val; + } + ll get2(int p) { + return get(0, p) * p + get(1, p); + } + ll query(int l, int r) { + return get2(r+1) - get2(l); + } + void update(int l, int r, ll x) { + add(0, l+1, x), add(0, r+2, -x); + add(1, l+1, -x*l), add(1, r+2, x*(r+1)); + } +}; +``` diff --git a/content/docs/Estruturas/bitSortTree.md b/content/docs/Estruturas/bitSortTree.md new file mode 100644 index 0000000..4a21198 --- /dev/null +++ b/content/docs/Estruturas/bitSortTree.md @@ -0,0 +1,62 @@ +--- +weight: 10 +title: "BIT-Sort Tree" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Tipo uma MergeSort Tree usando Bit + + Apesar da complexidade ser pior, fica melhor na pratica. + + + + query(l, r, k) retorna o numero de elementos menores que k + + no intervalo [l, r] + + + + Usa O(n log(n)) de memoria + + + + Complexidades: + + construir - O(n log^2(n)) + + query - O(log^2(n)) + + + +Link original: [bitSortTree.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Estruturas/bitSortTree.cpp) + +## Código +```cpp +template struct ms_bit { + int n; + vector> bit; + + ms_bit(vector& v) : n(v.size()), bit(n+1) { + for (int i = 0; i < n; i++) + for (int j = i+1; j <= n; j += j&-j) + bit[j].push_back(v[i]); + for (int i = 1; i <= n; i++) + sort(bit[i].begin(), bit[i].end()); + } + + int p_query(int i, T k) { + int ret = 0; + for (i++; i; i -= i&-i) + ret += lower_bound(bit[i].begin(), bit[i].end(), k) - bit[i].begin(); + return ret; + } + int query(int l, int r, T k) { + return p_query(r, k) - p_query(l-1, k); + } +}; +``` diff --git a/content/docs/Estruturas/cht.md b/content/docs/Estruturas/cht.md new file mode 100644 index 0000000..3caafaf --- /dev/null +++ b/content/docs/Estruturas/cht.md @@ -0,0 +1,57 @@ +--- +weight: 10 +title: "Convex Hull Trick Estatico" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + adds tem que serem feitos em ordem de slope + + queries tem que ser feitas em ordem de x + + + + add O(1) amortizado, get O(1) amortizado + + + +Link original: [cht.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Estruturas/cht.cpp) + +## Código +```cpp +struct CHT { + int it; + vector a, b; + CHT():it(0){} + ll eval(int i, ll x){ + return a[i]*x + b[i]; + } + bool useless(){ + int sz = a.size(); + int r = sz-1, m = sz-2, l = sz-3; +#warning cuidado com overflow! + return (b[l] - b[r])*(a[m] - a[l]) < + (b[l] - b[m])*(a[r] - a[l]); + } + void add(ll A, ll B){ + a.push_back(A); b.push_back(B); + while (!a.empty()){ + if ((a.size() < 3) || !useless()) break; + a.erase(a.end() - 2); + b.erase(b.end() - 2); + } + it = min(it, int(a.size()) - 1); + } + ll get(ll x){ + while (it+1 < a.size()){ + if (eval(it+1, x) > eval(it, x)) it++; + else break; + } + return eval(it, x); + } +}; +``` diff --git a/content/docs/Estruturas/chtDinamico.md b/content/docs/Estruturas/chtDinamico.md new file mode 100644 index 0000000..cea145e --- /dev/null +++ b/content/docs/Estruturas/chtDinamico.md @@ -0,0 +1,73 @@ +--- +weight: 10 +title: "Convex Hull Trick Dinamico" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + para double, use LINF = 1/.0, div(a, b) = a/b + + update(x) atualiza o ponto de intersecao da reta x + + overlap(x) verifica se a reta x sobrepoe a proxima + + add(a, b) adiciona reta da forma ax + b + + query(x) computa maximo de ax + b para entre as retas + + + + O(log(n)) amortizado por insercao + + O(log(n)) por query + + + +Link original: [chtDinamico.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Estruturas/chtDinamico.cpp) + +## Código +```cpp +struct Line { + mutable ll a, b, p; + bool operator<(const Line& o) const { return a < o.a; } + bool operator<(ll x) const { return p < x; } +}; + +struct dynamic_hull : multiset> { + ll div(ll a, ll b) { + return a / b - ((a ^ b) < 0 and a % b); + } + + void update(iterator x) { + if (next(x) == end()) x->p = LINF; + else if (x->a == next(x)->a) x->p = x->b >= next(x)->b ? LINF : -LINF; + else x->p = div(next(x)->b - x->b, x->a - next(x)->a); + } + + bool overlap(iterator x) { + update(x); + if (next(x) == end()) return 0; + if (x->a == next(x)->a) return x->b >= next(x)->b; + return x->p >= next(x)->p; + } + + void add(ll a, ll b) { + auto x = insert({a, b, 0}); + while (overlap(x)) erase(next(x)), update(x); + if (x != begin() and !overlap(prev(x))) x = prev(x), update(x); + while (x != begin() and overlap(prev(x))) + x = prev(x), erase(next(x)), update(x); + } + + ll query(ll x) { + assert(!empty()); + auto l = *lower_bound(x); +#warning cuidado com overflow! + return l.a * x + l.b; + } +}; +``` diff --git a/content/docs/Estruturas/dsu.md b/content/docs/Estruturas/dsu.md new file mode 100644 index 0000000..eb955a6 --- /dev/null +++ b/content/docs/Estruturas/dsu.md @@ -0,0 +1,141 @@ +--- +weight: 10 +title: "DSU" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Une dois conjuntos e acha a qual conjunto um elemento pertence por seu id + + + + find e unite: O(a(n)) ~= O(1) amortizado + + + +Link original: [dsu.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Estruturas/dsu.cpp) + +## Código +```cpp +struct dsu { + vector id, sz; + + dsu(int n) : id(n), sz(n, 1) { iota(id.begin(), id.end(), 0); } + + int find(int a) { return a == id[a] ? a : id[a] = find(id[a]); } + + void unite(int a, int b) { + a = find(a), b = find(b); + if (a == b) return; + if (sz[a] < sz[b]) swap(a, b); + sz[a] += sz[b], id[b] = a; + } +}; + +// DSU de bipartido +// +// Une dois vertices e acha a qual componente um vertice pertence +// Informa se a componente de um vertice e bipartida +// +// find e unite: O(log(n)) + +struct dsu { + vector id, sz, bip, c; + + dsu(int n) : id(n), sz(n, 1), bip(n, 1), c(n) { + iota(id.begin(), id.end(), 0); + } + + int find(int a) { return a == id[a] ? a : find(id[a]); } + int color(int a) { return a == id[a] ? c[a] : c[a] ^ color(id[a]); } + + void unite(int a, int b) { + bool change = color(a) == color(b); + a = find(a), b = find(b); + if (a == b) { + if (change) bip[a] = 0; + return; + } + + if (sz[a] < sz[b]) swap(a, b); + if (change) c[b] = 1; + sz[a] += sz[b], id[b] = a, bip[a] &= bip[b]; + } +}; + + +// DSU Persistente +// +// Persistencia parcial, ou seja, tem que ir +// incrementando o 't' no une +// +// find e unite: O(log(n)) + +struct dsu { + vector id, sz, ti; + + dsu(int n) : id(n), sz(n, 1), ti(n, -INF) { + iota(id.begin(), id.end(), 0); + } + + int find(int a, int t) { + if (id[a] == a or ti[a] > t) return a; + return find(id[a], t); + } + + void unite(int a, int b, int t) { + a = find(a, t), b = find(b, t); + if (a == b) return; + if (sz[a] < sz[b]) swap(a, b); + sz[a] += sz[b], id[b] = a, ti[b] = t; + } +}; + +// DSU com rollback +// +// checkpoint(): salva o estado atual de todas as variaveis +// rollback(): retorna para o valor das variaveis para +// o ultimo checkpoint +// +// Sempre que uma variavel muda de valor, adiciona na stack +// +// find e unite: O(log(n)) +// checkpoint: O(1) +// rollback: O(m) em que m e o numero de vezes que alguma +// variavel mudou de valor desde o ultimo checkpoint + +struct dsu { + vector id, sz; + stack>> st; + + dsu(int n) : id(n), sz(n, 1) { + iota(id.begin(), id.end(), 0), st.emplace(); + } + + void save(int &x) { st.top().emplace(x, x); } + + void checkpoint() { st.emplace(); } + + void rollback() { + while(st.top().size()) { + auto [end, val] = st.top().top(); st.top().pop(); + end = val; + } + st.pop(); + } + + int find(int a) { return a == id[a] ? a : find(id[a]); } + + void unite(int a, int b) { + a = find(a), b = find(b); + if (a == b) return; + if (sz[a] < sz[b]) swap(a, b); + save(sz[a]), save(id[b]); + sz[a] += sz[b], id[b] = a; + } +}; +``` diff --git a/content/docs/Estruturas/lichao.md b/content/docs/Estruturas/lichao.md new file mode 100644 index 0000000..5d0f42c --- /dev/null +++ b/content/docs/Estruturas/lichao.md @@ -0,0 +1,68 @@ +--- +weight: 10 +title: "Li-Chao Tree" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Adiciona retas (ax+b), e computa o minimo entre as retas + + em um dado 'x' + + Cuidado com overflow! + + Se tiver overflow, tenta comprimir o 'x' ou usar + + convex hull trick + + + + O(log(MA-MI)), O(n) de memoria + + + +Link original: [lichao.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Estruturas/lichao.cpp) + +## Código +```cpp +template struct lichao { + struct line { + ll a, b; + array ch; + line(ll a_ = 0, ll b_ = LINF) : + a(a_), b(b_), ch({-1, -1}) {} + ll operator ()(ll x) { return a*x + b; } + }; + vector ln; + + int ch(int p, int d) { + if (ln[p].ch[d] == -1) { + ln[p].ch[d] = ln.size(); + ln.emplace_back(); + } + return ln[p].ch[d]; + } + lichao() { ln.emplace_back(); } + + void add(line s, ll l=MI, ll r=MA, int p=0) { + ll m = (l+r)/2; + bool L = s(l) < ln[p](l); + bool M = s(m) < ln[p](m); + bool R = s(r) < ln[p](r); + if (M) swap(ln[p], s), swap(ln[p].ch, s.ch); + if (s.b == LINF) return; + if (L != M) add(s, l, m-1, ch(p, 0)); + else if (R != M) add(s, m+1, r, ch(p, 1)); + } + ll query(int x, ll l=MI, ll r=MA, int p=0) { + ll m = (l+r)/2, ret = ln[p](x); + if (ret == LINF) return ret; + if (x < m) return min(ret, query(x, l, m-1, ch(p, 0))); + return min(ret, query(x, m+1, r, ch(p, 1))); + } +}; +``` diff --git a/content/docs/Estruturas/lichaoLazy.md b/content/docs/Estruturas/lichaoLazy.md new file mode 100644 index 0000000..c5d40e0 --- /dev/null +++ b/content/docs/Estruturas/lichaoLazy.md @@ -0,0 +1,115 @@ +--- +weight: 10 +title: "Li-Chao Tree - Lazy" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Sendo N = MA-MI: + + insert({a, b}) minimiza tudo com ax+b - O(log N) + + insert({a, b}, l, r) minimiza com ax+b no range [l, r] - O(log^2 N) + + shift({a, b}) soma ax+b em tudo - O(1) + + shift({a, b}, l, r) soma ax+b no range [l, r] - O(log^2 N) + + query(x) retorna o valor da posicao x - O(log N) + + + + No inicio eh tudo LINF, se inserir {0, 0} fica tudo 0 + + + + O(n log N) de memoria ; O(n) de memoria se nao usar as operacoes de range + + + +Link original: [lichaoLazy.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Estruturas/lichaoLazy.cpp) + +## Código +```cpp +template struct lichao { + struct line { + ll a, b; + ll la, lb; // lazy + array ch; + line(ll a_ = 0, ll b_ = LINF) : + a(a_), b(b_), la(0), lb(0), ch({-1, -1}) {} + ll operator ()(ll x) { return a*x + b; } + }; + vector ln; + + int ch(int p, int d) { + if (ln[p].ch[d] == -1) { + ln[p].ch[d] = ln.size(); + ln.emplace_back(); + } + return ln[p].ch[d]; + } + lichao() { ln.emplace_back(); } + + void prop(int p, int l, int r) { + if (ln[p].la == 0 and ln[p].lb == 0) return; + ln[p].a += ln[p].la, ln[p].b += ln[p].lb; + if (l != r) { + int pl = ch(p, 0), pr = ch(p, 1); + ln[pl].la += ln[p].la, ln[pl].lb += ln[p].lb; + ln[pr].la += ln[p].la, ln[pr].lb += ln[p].lb; + } + ln[p].la = ln[p].lb = 0; + } + + ll query(int x, int p=0, int l=MI, int r=MA) { + prop(p, l, r); + ll ret = ln[p](x); + if (ln[p].ch[0] == -1 and ln[p].ch[1] == -1) return ret; + int m = l + (r-l)/2; + if (x <= m) return min(ret, query(x, ch(p, 0), l, m)); + return min(ret, query(x, ch(p, 1), m+1, r)); + } + + void push(line s, int p, int l, int r) { + prop(p, l, r); + int m = l + (r-l)/2; + bool L = s(l) < ln[p](l); + bool M = s(m) < ln[p](m); + bool R = s(r) < ln[p](r); + if (M) swap(ln[p].a, s.a), swap(ln[p].b, s.b); + if (s.b == LINF) return; + if (L != M) push(s, ch(p, 0), l, m); + else if (R != M) push(s, ch(p, 1), m+1, r); + } + void insert(line s, int a=MI, int b=MA, int p=0, int l=MI, int r=MA) { + prop(p, l, r); + if (a <= l and r <= b) return push(s, p, l, r); + if (b < l or r < a) return; + int m = l + (r-l)/2; + insert(s, a, b, ch(p, 0), l, m); + insert(s, a, b, ch(p, 1), m+1, r); + } + + void shift(line s, int a=MI, int b=MA, int p=0, int l=MI, int r=MA) { + prop(p, l, r); + int m = l + (r-l)/2; + if (a <= l and r <= b) { + ln[p].la += s.a, ln[p].lb += s.b; + return; + } + if (b < l or r < a) return; + if (ln[p].b != LINF) { + push(ln[p], ch(p, 0), l, m); + push(ln[p], ch(p, 1), m+1, r); + ln[p].a = 0, ln[p].b = LINF; + } + shift(s, a, b, ch(p, 0), l, m); + shift(s, a, b, ch(p, 1), m+1, r); + } +}; +``` diff --git a/content/docs/Estruturas/mergeSortTree.md b/content/docs/Estruturas/mergeSortTree.md new file mode 100644 index 0000000..cc73002 --- /dev/null +++ b/content/docs/Estruturas/mergeSortTree.md @@ -0,0 +1,148 @@ +--- +weight: 10 +title: "MergeSort Tree" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Se for construida sobre um array: + + count(i, j, a, b) retorna quantos + + elementos de v[i..j] pertencem a [a, b] + + report(i, j, a, b) retorna os indices dos + + elementos de v[i..j] que pertencem a [a, b] + + retorna o vetor ordenado + + Se for construida sobre pontos (x, y): + + count(x1, x2, y1, y2) retorna quantos pontos + + pertencem ao retangulo (x1, y1), (x2, y2) + + report(x1, x2, y1, y2) retorna os indices dos pontos que + + pertencem ao retangulo (x1, y1), (x2, y2) + + retorna os pontos ordenados lexicograficamente + + (assume x1 <= x2, y1 <= y2) + + + + kth(y1, y2, k) retorna o indice do ponto com k-esimo menor + + x dentre os pontos que possuem y em [y1, y2] (0 based) + + Se quiser usar para achar k-esimo valor em range, construir + + com ms_tree t(v, true), e chamar kth(l, r, k) + + + + Usa O(n log(n)) de memoria + + + + Complexidades: + + construir - O(n log(n)) + + count - O(log(n)) + + report - O(log(n) + k) para k indices retornados + + kth - O(log(n)) + + + +Link original: [mergeSortTree.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Estruturas/mergeSortTree.cpp) + +## Código +```cpp +template struct ms_tree { + vector> v; + int n; + vector>> t; // {y, idx, left} + vector vy; + + ms_tree(vector>& vv) : n(vv.size()), t(4*n), vy(n) { + for (int i = 0; i < n; i++) v.push_back({vv[i].first, vv[i].second, i}); + sort(v.begin(), v.end()); + build(1, 0, n-1); + for (int i = 0; i < n; i++) vy[i] = get<0>(t[1][i+1]); + } + ms_tree(vector& vv, bool inv = false) { // inv: inverte indice e valor + vector> v2; + for (int i = 0; i < vv.size(); i++) + inv ? v2.push_back({vv[i], i}) : v2.push_back({i, vv[i]}); + *this = ms_tree(v2); + } + void build(int p, int l, int r) { + t[p].push_back({get<0>(v[l]), get<0>(v[r]), 0}); // {min_x, max_x, 0} + if (l == r) return t[p].push_back({get<1>(v[l]), get<2>(v[l]), 0}); + int m = (l+r)/2; + build(2*p, l, m), build(2*p+1, m+1, r); + + int L = 0, R = 0; + while (t[p].size() <= r-l+1) { + int left = get<2>(t[p].back()); + if (L > m-l or (R+m+1 <= r and t[2*p+1][1+R] < t[2*p][1+L])) { + t[p].push_back(t[2*p+1][1 + R++]); + get<2>(t[p].back()) = left; + continue; + } + t[p].push_back(t[2*p][1 + L++]); + get<2>(t[p].back()) = left+1; + } + } + + int get_l(T y) { return lower_bound(vy.begin(), vy.end(), y) - vy.begin(); } + int get_r(T y) { return upper_bound(vy.begin(), vy.end(), y) - vy.begin(); } + + int count(T x1, T x2, T y1, T y2) { + function dfs = [&](int p, int l, int r) { + if (l == r or x2 < get<0>(t[p][0]) or get<1>(t[p][0]) < x1) return 0; + if (x1 <= get<0>(t[p][0]) and get<1>(t[p][0]) <= x2) return r-l; + int nl = get<2>(t[p][l]), nr = get<2>(t[p][r]); + return dfs(2*p, nl, nr) + dfs(2*p+1, l-nl, r-nr); + }; + return dfs(1, get_l(y1), get_r(y2)); + } + vector report(T x1, T x2, T y1, T y2) { + vector ret; + function dfs = [&](int p, int l, int r) { + if (l == r or x2 < get<0>(t[p][0]) or get<1>(t[p][0]) < x1) return; + if (x1 <= get<0>(t[p][0]) and get<1>(t[p][0]) <= x2) { + for (int i = l; i < r; i++) ret.push_back(get<1>(t[p][i+1])); + return; + } + int nl = get<2>(t[p][l]), nr = get<2>(t[p][r]); + dfs(2*p, nl, nr), dfs(2*p+1, l-nl, r-nr); + }; + dfs(1, get_l(y1), get_r(y2)); + return ret; + } + int kth(T y1, T y2, int k) { + function dfs = [&](int p, int l, int r) { + if (k >= r-l) { + k -= r-l; + return -1; + } + if (r-l == 1) return get<1>(t[p][l+1]); + int nl = get<2>(t[p][l]), nr = get<2>(t[p][r]); + int left = dfs(2*p, nl, nr); + if (left != -1) return left; + return dfs(2*p+1, l-nl, r-nr); + }; + return dfs(1, get_l(y1), get_r(y2)); + } +}; +``` diff --git a/content/docs/Estruturas/minqueueDeque.md b/content/docs/Estruturas/minqueueDeque.md new file mode 100644 index 0000000..fff8226 --- /dev/null +++ b/content/docs/Estruturas/minqueueDeque.md @@ -0,0 +1,35 @@ +--- +weight: 10 +title: "Min queue - deque" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Tudo O(1) amortizado + + + +Link original: [minqueueDeque.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Estruturas/minqueueDeque.cpp) + +## Código +```cpp +template struct minqueue { + deque> q; + + void push(T x) { + int ct = 1; + while (q.size() and x < q.front().first) + ct += q.front().second, q.pop_front(); + q.emplace_front(x, ct); + } + void pop() { + if (q.back().second > 1) q.back().second--; + else q.pop_back(); + } + T min() { return q.back().first; } +}; +``` diff --git a/content/docs/Estruturas/minqueueStack.md b/content/docs/Estruturas/minqueueStack.md new file mode 100644 index 0000000..29d9f25 --- /dev/null +++ b/content/docs/Estruturas/minqueueStack.md @@ -0,0 +1,57 @@ +--- +weight: 10 +title: "Min queue - stack" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Tudo O(1) amortizado + + + +Link original: [minqueueStack.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Estruturas/minqueueStack.cpp) + +## Código +```cpp +template struct minstack { + stack> s; + + void push(T x) { + if (!s.size()) s.push({x, x}); + else s.emplace(x, std::min(s.top().second, x)); + } + T top() { return s.top().first; } + T pop() { + T ans = s.top().first; + s.pop(); + return ans; + } + int size() { return s.size(); } + T min() { return s.top().second; } +}; + +template struct minqueue { + minstack s1, s2; + + void push(T x) { s1.push(x); } + void move() { + if (s2.size()) return; + while (s1.size()) { + T x = s1.pop(); + s2.push(x); + } + } + T front() { return move(), s2.top(); } + T pop() { return move(), s2.pop(); } + int size() { return s1.size()+s2.size(); } + T min() { + if (!s1.size()) return s2.min(); + else if (!s2.size()) return s1.min(); + return std::min(s1.min(), s2.min()); + } +}; +``` diff --git a/content/docs/Estruturas/orderStatisticSet.md b/content/docs/Estruturas/orderStatisticSet.md new file mode 100644 index 0000000..38f7e97 --- /dev/null +++ b/content/docs/Estruturas/orderStatisticSet.md @@ -0,0 +1,44 @@ +--- +weight: 10 +title: "Order Statistic Set" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Funciona do C++11 pra cima + + + +Link original: [orderStatisticSet.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Estruturas/orderStatisticSet.cpp) + +## Código +```cpp +#include +#include +using namespace __gnu_pbds; +template + using ord_set = tree, rb_tree_tag, + tree_order_statistics_node_update>; + +// para declarar: +// ord_set s; +// coisas do set normal funcionam: +// for (auto i : s) cout << i << endl; +// cout << s.size() << endl; +// k-esimo maior elemento O(log|s|): +// k=0: menor elemento +// cout << *s.find_by_order(k) << endl; +// quantos sao menores do que k O(log|s|): +// cout << s.order_of_key(k) << endl; + +// Para fazer um multiset, tem que +// usar ord_set> com o +// segundo parametro sendo algo para diferenciar +// os ementos iguais. +// s.order_of_key({k, -INF}) vai retornar o +// numero de elementos < k +``` diff --git a/content/docs/Estruturas/priorityQueueDs.md b/content/docs/Estruturas/priorityQueueDs.md new file mode 100644 index 0000000..878b972 --- /dev/null +++ b/content/docs/Estruturas/priorityQueueDs.md @@ -0,0 +1,96 @@ +--- +weight: 10 +title: "Priority Queue DS" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Mantem updates aplicados em uma estrutura de dados + + que permita rollback e nao seja amortizada. + + Cada update possui uma prioridade, + + sendo possivel remover o update com maior prioridade. + + Os updates devem ser comutativos, ou seja, o estado + + da estrutura deve ser o mesmo independente da ordem + + que eles sejam aplicados. + + + + Complexidades: + + update - O(log(n) + T(n)) + + query - T(n) + + pop - O(log(n) * T(n)) amortizado + + + + onde T(n) eh a complexidade do update + + + + assumes all priorities are distinct + +Link original: [priorityQueueDs.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Estruturas/priorityQueueDs.cpp) + +## Código +```cpp +template struct priority_queue_ds { + DS D; + vector> upd; // {u, p, idx_in_pos} + set> st; + vector pos; + + priority_queue_ds(int n) : D(n) {} + + void update(UPD u, int p) { + D.update(u); + st.emplace(p, pos.size()); + upd.emplace_back(u, p, pos.size()); + pos.push_back(upd.size() - 1); + } + + int query(int a) { + return D.find(a); + } + + void pop() { + int k = 1, min_p; // k = number of pops we will do + vector> small, big; + auto it = st.end(); + for (int qt = 0; qt++ < (k+1)/2;) { + it--; + min_p = it->first; + int i = pos[it->second]; + if (qt > 1) big.push_back(upd[i]); + k = max(k, upd.size() - i); + } + + for (int i = 0; i < k; i++) { + D.rollback(); + auto [u, p, idx] = upd.rbegin()[i]; + if (p < min_p) small.emplace_back(u, p, idx); + } + + st.erase(prev(st.end())); + upd.erase(upd.end() - k, upd.end()); + + small.insert(small.end(), big.rbegin(), big.rend()); + for (auto [u, p, idx] : small) { + D.update(u); + upd.emplace_back(u, p, idx); + pos[idx] = upd.size() - 1; + } + } +}; +``` diff --git a/content/docs/Estruturas/rangeColor.md b/content/docs/Estruturas/rangeColor.md new file mode 100644 index 0000000..4b2a20b --- /dev/null +++ b/content/docs/Estruturas/rangeColor.md @@ -0,0 +1,60 @@ +--- +weight: 10 +title: "Range color" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + update(l, r, c) colore o range [l, r] com a cor c, + + e retorna os ranges que foram coloridos {l, r, cor} + + query(i) returna a cor da posicao i + + + + Complexidades (para q operacoes): + + update - O(log(q)) amortizado + + query - O(log(q)) + + + +Link original: [rangeColor.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Estruturas/rangeColor.cpp) + +## Código +```cpp +template struct color { + set> se; + + vector> update(int l, int r, T val) { + auto it = se.upper_bound({r, INF, val}); + if (it != se.begin() and get<1>(*prev(it)) > r) { + auto [L, R, V] = *--it; + se.erase(it); + se.emplace(L, r, V), se.emplace(r+1, R, V); + } + it = se.lower_bound({l, -INF, val}); + if (it != se.begin() and get<1>(*prev(it)) >= l) { + auto [L, R, V] = *--it; + se.erase(it); + se.emplace(L, l-1, V), it = se.emplace(l, R, V).first; + } + vector> ret; + for (; it != se.end() and get<0>(*it) <= r; it = se.erase(it)) + ret.push_back(*it); + se.emplace(l, r, val); + return ret; + } + T query(int i) { + auto it = se.upper_bound({i, INF, T()}); + if (it == se.begin() or get<1>(*--it) < i) return -1; // nao tem + return get<2>(*it); + } +}; +``` diff --git a/content/docs/Estruturas/rmq.md b/content/docs/Estruturas/rmq.md new file mode 100644 index 0000000..f2b57bf --- /dev/null +++ b/content/docs/Estruturas/rmq.md @@ -0,0 +1,52 @@ +--- +weight: 10 +title: "RMQ - min queue" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + O(n) pra buildar, query O(1) + + Se tiver varios minimos, retorna + + o de menor indice + + + +Link original: [rmq.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Estruturas/rmq.cpp) + +## Código +```cpp +template struct rmq { + vector v; + int n; static const int b = 30; + vector mask, t; + + int op(int x, int y) { return v[x] <= v[y] ? x : y; } + int msb(int x) { return __builtin_clz(1)-__builtin_clz(x); } + int small(int r, int sz = b) { return r-msb(mask[r]&((1<& v_) : v(v_), n(v.size()), mask(n), t(n) { + for (int i = 0, at = 0; i < n; mask[i++] = at |= 1) { + at = (at<<1)&((1< y) return op(small(l+b-1), small(r)); + int j = msb(y-x+1); + int ans = op(small(l+b-1), op(t[n/b*j+x], t[n/b*j+y-(1< struct SlopeTrick { + T inf = numeric_limits::max() / 3; + T min_f; + priority_queue, less<>> L; + priority_queue, greater<>> R; + T add_l, add_r; + + T top_R() { + if (R.empty()) return inf; + else return R.top() + add_r; + } + + T pop_R() { + T val = top_R(); + if (R.size()) R.pop(); + return val; + } + + T top_L() { + if (L.empty()) return -inf; + else return L.top() + add_l; + } + + T pop_L() { + T val = top_L(); + if (L.size()) L.pop(); + return val; + } + + size_t size() { + return L.size() + R.size(); + } + + SlopeTrick() : min_f(0), add_l(0), add_r(0) {}; + + // return {min f(x), lx, rx} + // Em que [lx, rx] eh o intervalo que atinge o minimo + array query() { + return {min_f, top_L(), top_R()}; + } + + // f(x) += a + void add_all(T a) { + min_f += a; + } + + // add \_ + // f(x) += max(a - x, 0) + void add_a_minus_x(T a) { + min_f += max(T(0), a - top_R()); + R.push(a - add_r); + L.push(pop_R() - add_l); + } + + // add _/ + // f(x) += max(x - a, 0) + void add_x_minus_a(T a) { + min_f += max(T(0), top_L() - a); + L.push(a - add_l); + R.push(pop_L() - add_r); + } + + // add \/ + // f(x) += abs(x - a) + void add_abs(T a) { + add_a_minus_x(a); + add_x_minus_a(a); + } + + // \/ -> \_ + // f_{new} (x) = min f(y) (y <= x) + void clear_right() { + while (R.size()) R.pop(); + } + + // \/ -> _/ + // f_{new} (x) = min f(y) (y >= x) + void clear_left() { + while (L.size()) L.pop(); + } + + // \/ -> \_/ + // f_{new} (x) = min f(y) (x-b <= y <= x-a) + void shift(T a, T b) { + assert(a <= b); + add_l += a; + add_r += b; + } + + // \/. -> .\/ + // f_{new} (x) = f(x - a) + void shift(T a) { + shift(a, a); + } + + // Retorna f(x) + // O(size) + T get(T x) { + auto L2 = L; + auto R2 = R; + T ret = min_f; + while (L.size()) { + ret += max(T(0), pop_L() - x); + } + while (R.size()) { + ret += max(T(0), x - pop_R()); + } + L = L2, R = R2; + return ret; + } + + // O(min(size, st.size)) + void merge(SlopeTrick &st) { + if (st.size() > size()) { + swap(*this, st); + } + while (st.R.size()) { + add_x_minus_a(st.pop_R()); + } + while (st.L.size()) { + add_a_minus_x(st.pop_L()); + } + min_f += st.min_f; + } +}; + +``` diff --git a/content/docs/Estruturas/sparseTable.md b/content/docs/Estruturas/sparseTable.md new file mode 100644 index 0000000..8db92f3 --- /dev/null +++ b/content/docs/Estruturas/sparseTable.md @@ -0,0 +1,43 @@ +--- +weight: 10 +title: "Sparse Table" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Resolve RMQ + + MAX2 = log(MAX) + + + + Complexidades: + + build - O(n log(n)) + + query - O(1) + + + +Link original: [sparseTable.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Estruturas/sparseTable.cpp) + +## Código +```cpp +namespace sparse { + int m[MAX2][MAX], n; + void build(int n2, int* v) { + n = n2; + for (int i = 0; i < n; i++) m[0][i] = v[i]; + for (int j = 1; (1<= c-len; i--) m[j][i] = op(v[i], m[j][i+1]); + } + } + } + int query(int l, int r) { + if (l == r) return v[l]; + int j = __builtin_clz(1) - __builtin_clz(l^r); + return op(m[j][l], m[j][r]); + } +} +``` diff --git a/content/docs/Estruturas/splaytree.md b/content/docs/Estruturas/splaytree.md new file mode 100644 index 0000000..60a08cb --- /dev/null +++ b/content/docs/Estruturas/splaytree.md @@ -0,0 +1,143 @@ +--- +weight: 10 +title: "Splay Tree" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + SEMPRE QUE DESCER NA ARVORE, DAR SPLAY NO + + NODE MAIS PROFUNDO VISITADO + + Todas as operacoes sao O(log(n)) amortizado + + Se quiser colocar mais informacao no node, + + mudar em 'update' + + + +Link original: [splaytree.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Estruturas/splaytree.cpp) + +## Código +```cpp +template struct splaytree { + struct node { + node *ch[2], *p; + int sz; + T val; + node(T v) { + ch[0] = ch[1] = p = NULL; + sz = 1; + val = v; + } + void update() { + sz = 1; + for (int i = 0; i < 2; i++) if (ch[i]) { + sz += ch[i]->sz; + } + } + }; + + node* root; + + splaytree() { root = NULL; } + splaytree(const splaytree& t) { + throw logic_error("Nao copiar a splaytree!"); + } + ~splaytree() { + vector q = {root}; + while (q.size()) { + node* x = q.back(); q.pop_back(); + if (!x) continue; + q.push_back(x->ch[0]), q.push_back(x->ch[1]); + delete x; + } + } + + void rotate(node* x) { // x vai ficar em cima + node *p = x->p, *pp = p->p; + if (pp) pp->ch[pp->ch[1] == p] = x; + bool d = p->ch[0] == x; + p->ch[!d] = x->ch[d], x->ch[d] = p; + if (p->ch[!d]) p->ch[!d]->p = p; + x->p = pp, p->p = x; + p->update(), x->update(); + } + node* splay(node* x) { + if (!x) return x; + root = x; + while (x->p) { + node *p = x->p, *pp = p->p; + if (!pp) return rotate(x), x; // zig + if ((pp->ch[0] == p)^(p->ch[0] == x)) + rotate(x), rotate(x); // zigzag + else rotate(p), rotate(x); // zigzig + } + return x; + } + node* insert(T v, bool lb=0) { + if (!root) return lb ? NULL : root = new node(v); + node *x = root, *last = NULL;; + while (1) { + bool d = x->val < v; + if (!d) last = x; + if (x->val == v) break; + if (x->ch[d]) x = x->ch[d]; + else { + if (lb) break; + x->ch[d] = new node(v); + x->ch[d]->p = x; + x = x->ch[d]; + break; + } + } + splay(x); + return lb ? splay(last) : x; + } + int size() { return root ? root->sz : 0; } + int count(T v) { return insert(v, 1) and root->val == v; } + node* lower_bound(T v) { return insert(v, 1); } + void erase(T v) { + if (!count(v)) return; + node *x = root, *l = x->ch[0]; + if (!l) { + root = x->ch[1]; + if (root) root->p = NULL; + return delete x; + } + root = l, l->p = NULL; + while (l->ch[1]) l = l->ch[1]; + splay(l); + l->ch[1] = x->ch[1]; + if (l->ch[1]) l->ch[1]->p = l; + delete x; + l->update(); + } + int order_of_key(T v) { + if (!lower_bound(v)) return root ? root->sz : 0; + return root->ch[0] ? root->ch[0]->sz : 0; + } + node* find_by_order(int k) { + if (k >= size()) return NULL; + node* x = root; + while (1) { + if (x->ch[0] and x->ch[0]->sz >= k+1) x = x->ch[0]; + else { + if (x->ch[0]) k -= x->ch[0]->sz; + if (!k) return splay(x); + k--, x = x->ch[1]; + } + } + } + T min() { + node* x = root; + while (x->ch[0]) x = x->ch[0]; // max -> ch[1] + return splay(x)->val; + } +}; +``` diff --git a/content/docs/Estruturas/splaytreeImplicita.md b/content/docs/Estruturas/splaytreeImplicita.md new file mode 100644 index 0000000..dcfc037 --- /dev/null +++ b/content/docs/Estruturas/splaytreeImplicita.md @@ -0,0 +1,195 @@ +--- +weight: 10 +title: "Splay Tree Implicita" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + vector da NASA + + Um pouco mais rapido q a treap + + O construtor a partir do vector + + eh linear, todas as outras operacoes + + custam O(log(n)) amortizado + + + +Link original: [splaytreeImplicita.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Estruturas/splaytreeImplicita.cpp) + +## Código +```cpp +template struct splay { + struct node { + node *ch[2], *p; + int sz; + T val, sub, lazy; + bool rev; + node(T v) { + ch[0] = ch[1] = p = NULL; + sz = 1; + sub = val = v; + lazy = 0; + rev = false; + } + void prop() { + if (lazy) { + val += lazy, sub += lazy*sz; + if (ch[0]) ch[0]->lazy += lazy; + if (ch[1]) ch[1]->lazy += lazy; + } + if (rev) { + swap(ch[0], ch[1]); + if (ch[0]) ch[0]->rev ^= 1; + if (ch[1]) ch[1]->rev ^= 1; + } + lazy = 0, rev = 0; + } + void update() { + sz = 1, sub = val; + for (int i = 0; i < 2; i++) if (ch[i]) { + ch[i]->prop(); + sz += ch[i]->sz; + sub += ch[i]->sub; + } + } + }; + + node* root; + + splay() { root = NULL; } + splay(node* x) { + root = x; + if (root) root->p = NULL; + } + splay(vector v) { // O(n) + root = NULL; + for (T i : v) { + node* x = new node(i); + x->ch[0] = root; + if (root) root->p = x; + root = x; + root->update(); + } + } + splay(const splay& t) { + throw logic_error("Nao copiar a splay!"); + } + ~splay() { + vector q = {root}; + while (q.size()) { + node* x = q.back(); q.pop_back(); + if (!x) continue; + q.push_back(x->ch[0]), q.push_back(x->ch[1]); + delete x; + } + } + + int size(node* x) { return x ? x->sz : 0; } + void rotate(node* x) { // x vai ficar em cima + node *p = x->p, *pp = p->p; + if (pp) pp->ch[pp->ch[1] == p] = x; + bool d = p->ch[0] == x; + p->ch[!d] = x->ch[d], x->ch[d] = p; + if (p->ch[!d]) p->ch[!d]->p = p; + x->p = pp, p->p = x; + p->update(), x->update(); + } + node* splaya(node* x) { + if (!x) return x; + root = x, x->update(); + while (x->p) { + node *p = x->p, *pp = p->p; + if (!pp) return rotate(x), x; // zig + if ((pp->ch[0] == p)^(p->ch[0] == x)) + rotate(x), rotate(x); // zigzag + else rotate(p), rotate(x); // zigzig + } + return x; + } + node* find(int v) { + if (!root) return NULL; + node *x = root; + int key = 0; + while (1) { + x->prop(); + bool d = key + size(x->ch[0]) < v; + if (key + size(x->ch[0]) != v and x->ch[d]) { + if (d) key += size(x->ch[0])+1; + x = x->ch[d]; + } else break; + } + return splaya(x); + } + int size() { return root ? root->sz : 0; } + void join(splay& l) { // assume que l < *this + if (!size()) swap(root, l.root); + if (!size() or !l.size()) return; + node* x = l.root; + while (1) { + x->prop(); + if (!x->ch[1]) break; + x = x->ch[1]; + } + l.splaya(x), root->prop(), root->update(); + x->ch[1] = root, x->ch[1]->p = x; + root = l.root, l.root = NULL; + root->update(); + } + node* split(int v) { // retorna os elementos < v + if (v <= 0) return NULL; + if (v >= size()) { + node* ret = root; + root = NULL; + ret->update(); + return ret; + } + find(v); + node* l = root->ch[0]; + root->ch[0] = NULL; + if (l) l->p = NULL; + root->update(); + return l; + } + T& operator [](int i) { + find(i); + return root->val; + } + void push_back(T v) { // O(1) + node* r = new node(v); + r->ch[0] = root; + if (root) root->p = r; + root = r, root->update(); + } + T query(int l, int r) { + splay M(split(r+1)); + splay L(M.split(l)); + T ans = M.root->sub; + M.join(L), join(M); + return ans; + } + void update(int l, int r, T s) { + splay M(split(r+1)); + splay L(M.split(l)); + M.root->lazy += s; + M.join(L), join(M); + } + void reverse(int l, int r) { + splay M(split(r+1)); + splay L(M.split(l)); + M.root->rev ^= 1; + M.join(L), join(M); + } + void erase(int l, int r) { + splay M(split(r+1)); + splay L(M.split(l)); + join(L); + } +}; +``` diff --git a/content/docs/Estruturas/splitMergeSet.md b/content/docs/Estruturas/splitMergeSet.md new file mode 100644 index 0000000..07ca428 --- /dev/null +++ b/content/docs/Estruturas/splitMergeSet.md @@ -0,0 +1,196 @@ +--- +weight: 10 +title: "Split-Merge Set" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Representa um conjunto de inteiros nao negativos + + Todas as operacoes custam O(log(N)), + + em que N = maior elemento do set, + + exceto o merge, que custa O(log(N)) amortizado + + Usa O(min(N, n log(N))) de memoria, sendo 'n' o + + numero de elementos distintos no set + + + +Link original: [splitMergeSet.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Estruturas/splitMergeSet.cpp) + +## Código +```cpp +template struct sms { + struct node { + node *l, *r; + SIZE_T cnt; + node() : l(NULL), r(NULL), cnt(0) {} + void update() { + cnt = 0; + if (l) cnt += l->cnt; + if (r) cnt += r->cnt; + } + }; + + node* root; + T N; + + sms() : root(NULL), N(0) {} + sms(T v) : sms() { while (v >= N) N = 2*N+1; } + sms(const sms& t) : root(NULL), N(t.N) { + for (SIZE_T i = 0; i < t.size(); i++) { + T at = t[i]; + SIZE_T qt = t.count(at); + insert(at, qt); + i += qt-1; + } + } + sms(initializer_list v) : sms() { for (T i : v) insert(i); } + ~sms() { + vector q = {root}; + while (q.size()) { + node* x = q.back(); q.pop_back(); + if (!x) continue; + q.push_back(x->l), q.push_back(x->r); + delete x; + } + } + + friend void swap(sms& a, sms& b) { + swap(a.root, b.root), swap(a.N, b.N); + } + sms& operator =(const sms& v) { + sms tmp = v; + swap(tmp, *this); + return *this; + } + SIZE_T size() const { return root ? root->cnt : 0; } + SIZE_T count(node* x) const { return x ? x->cnt : 0; } + void clear() { + sms tmp; + swap(*this, tmp); + } + void expand(T v) { + for (; N < v; N = 2*N+1) if (root) { + node* nroot = new node(); + nroot->l = root; + root = nroot; + root->update(); + } + } + + node* insert(node* at, T idx, SIZE_T qt, T l, T r) { + if (!at) at = new node(); + if (l == r) { + at->cnt += qt; + if (!MULTI) at->cnt = 1; + return at; + } + T m = l + (r-l)/2; + if (idx <= m) at->l = insert(at->l, idx, qt, l, m); + else at->r = insert(at->r, idx, qt, m+1, r); + return at->update(), at; + } + void insert(T v, SIZE_T qt=1) { // insere 'qt' ocorrencias de 'v' + if (qt <= 0) return erase(v, -qt); + assert(v >= 0); + expand(v); + root = insert(root, v, qt, 0, N); + } + + node* erase(node* at, T idx, SIZE_T qt, T l, T r) { + if (!at) return at; + if (l == r) at->cnt = at->cnt < qt ? 0 : at->cnt - qt; + else { + T m = l + (r-l)/2; + if (idx <= m) at->l = erase(at->l, idx, qt, l, m); + else at->r = erase(at->r, idx, qt, m+1, r); + at->update(); + } + if (!at->cnt) delete at, at = NULL; + return at; + } + void erase(T v, SIZE_T qt=1) { // remove 'qt' ocorrencias de 'v' + if (v < 0 or v > N or !qt) return; + if (qt < 0) insert(v, -qt); + root = erase(root, v, qt, 0, N); + } + void erase_all(T v) { // remove todos os 'v' + if (v < 0 or v > N) return; + root = erase(root, v, numeric_limits::max(), 0, N); + } + + SIZE_T count(node* at, T a, T b, T l, T r) const { + if (!at or b < l or r < a) return 0; + if (a <= l and r <= b) return at->cnt; + T m = l + (r-l)/2; + return count(at->l, a, b, l, m) + count(at->r, a, b, m+1, r); + } + SIZE_T count(T v) const { return count(root, v, v, 0, N); } + SIZE_T order_of_key(T v) { return count(root, 0, v-1, 0, N); } + SIZE_T lower_bound(T v) { return order_of_key(v); } + + const T operator [](SIZE_T i) const { // i-esimo menor elemento + assert(i >= 0 and i < size()); + node* at = root; + T l = 0, r = N; + while (l < r) { + T m = l + (r-l)/2; + if (count(at->l) > i) at = at->l, r = m; + else { + i -= count(at->l); + at = at->r; l = m+1; + } + } + return l; + } + + node* merge(node* l, node* r) { + if (!l or !r) return l ? l : r; + if (!l->l and !l->r) { // folha + if (MULTI) l->cnt += r->cnt; + delete r; + return l; + } + l->l = merge(l->l, r->l), l->r = merge(l->r, r->r); + l->update(), delete r; + return l; + } + void merge(sms& s) { // mergeia dois sets + if (N > s.N) swap(*this, s); + expand(s.N); + root = merge(root, s.root); + s.root = NULL; + } + + node* split(node*& x, SIZE_T k) { + if (k <= 0 or !x) return NULL; + node* ret = new node(); + if (!x->l and !x->r) x->cnt -= k, ret->cnt += k; + else { + if (k <= count(x->l)) ret->l = split(x->l, k); + else { + ret->r = split(x->r, k - count(x->l)); + swap(x->l, ret->l); + } + ret->update(), x->update(); + } + if (!x->cnt) delete x, x = NULL; + return ret; + } + void split(SIZE_T k, sms& s) { // pega os 'k' menores + s.clear(); + s.root = split(root, min(k, size())); + s.N = N; + } + // pega os menores que 'k' + void split_val(T k, sms& s) { split(order_of_key(k), s); } +}; +``` diff --git a/content/docs/Estruturas/splitMergeSetLazy.md b/content/docs/Estruturas/splitMergeSetLazy.md new file mode 100644 index 0000000..c7762ad --- /dev/null +++ b/content/docs/Estruturas/splitMergeSetLazy.md @@ -0,0 +1,240 @@ +--- +weight: 10 +title: "Split-Merge Set - Lazy" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Representa um conjunto de inteiros nao negativos + + Todas as operacoes custam O(log(N)), + + em que N = maior elemento do set, + + exceto o merge e o insert_range, que custa O(log(N)) amortizado + + Usa O(min(N, n log(N))) de memoria, sendo 'n' o + + numero de elementos distintos no set + + + +Link original: [splitMergeSetLazy.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Estruturas/splitMergeSetLazy.cpp) + +## Código +```cpp +template struct sms { + struct node { + node *l, *r; + int cnt; + bool flip; + node() : l(NULL), r(NULL), cnt(0), flip(0) {} + void update() { + cnt = 0; + if (l) cnt += l->cnt; + if (r) cnt += r->cnt; + } + }; + + void prop(node* x, int size) { + if (!x or !x->flip) return; + x->flip = 0; + x->cnt = size - x->cnt; + if (size > 1) { + if (!x->l) x->l = new node(); + if (!x->r) x->r = new node(); + x->l->flip ^= 1; + x->r->flip ^= 1; + } + } + + node* root; + T N; + + sms() : root(NULL), N(0) {} + sms(T v) : sms() { while (v >= N) N = 2*N+1; } + sms(sms& t) : root(NULL), N(t.N) { + for (int i = 0; i < t.size(); i++) insert(t[i]); + } + sms(initializer_list v) : sms() { for (T i : v) insert(i); } + void destroy(node* r) { + vector q = {r}; + while (q.size()) { + node* x = q.back(); q.pop_back(); + if (!x) continue; + q.push_back(x->l), q.push_back(x->r); + delete x; + } + } + ~sms() { destroy(root); } + + friend void swap(sms& a, sms& b) { + swap(a.root, b.root), swap(a.N, b.N); + } + sms& operator =(const sms& v) { + sms tmp = v; + swap(tmp, *this); + return *this; + } + int count(node* x, T size) { + if (!x) return 0; + prop(x, size); + return x->cnt; + } + int size() { return count(root, N+1); } + void clear() { + sms tmp; + swap(*this, tmp); + } + void expand(T v) { + for (; N < v; N = 2*N+1) if (root) { + prop(root, N+1); + node* nroot = new node(); + nroot->l = root; + root = nroot; + root->update(); + } + } + + node* insert(node* at, T idx, T l, T r) { + if (!at) at = new node(); + else prop(at, r-l+1); + if (l == r) { + at->cnt = 1; + return at; + } + T m = l + (r-l)/2; + if (idx <= m) at->l = insert(at->l, idx, l, m); + else at->r = insert(at->r, idx, m+1, r); + return at->update(), at; + } + void insert(T v) { + assert(v >= 0); + expand(v); + root = insert(root, v, 0, N); + } + + node* erase(node* at, T idx, T l, T r) { + if (!at) return at; + prop(at, r-l+1); + if (l == r) at->cnt = 0; + else { + T m = l + (r-l)/2; + if (idx <= m) at->l = erase(at->l, idx, l, m); + else at->r = erase(at->r, idx, m+1, r); + at->update(); + } + return at; + } + void erase(T v) { + if (v < 0 or v > N) return; + root = erase(root, v, 0, N); + } + + int count(node* at, T a, T b, T l, T r) { + if (!at or b < l or r < a) return 0; + prop(at, r-l+1); + if (a <= l and r <= b) return at->cnt; + T m = l + (r-l)/2; + return count(at->l, a, b, l, m) + count(at->r, a, b, m+1, r); + } + int count(T v) { return count(root, v, v, 0, N); } + int order_of_key(T v) { return count(root, 0, v-1, 0, N); } + int lower_bound(T v) { return order_of_key(v); } + + const T operator [](int i) { // i-esimo menor elemento + assert(i >= 0 and i < size()); + node* at = root; + T l = 0, r = N; + while (l < r) { + prop(at, r-l+1); + T m = l + (r-l)/2; + if (count(at->l, m-l+1) > i) at = at->l, r = m; + else { + i -= count(at->l, r-m); + at = at->r; l = m+1; + } + } + return l; + } + + node* merge(node* a, node* b, T tam) { + if (!a or !b) return a ? a : b; + prop(a, tam), prop(b, tam); + if (b->cnt == tam) swap(a, b); + if (tam == 1 or a->cnt == tam) { + destroy(b); + return a; + } + a->l = merge(a->l, b->l, tam>>1), a->r = merge(a->r, b->r, tam>>1); + a->update(), delete b; + return a; + } + void merge(sms& s) { // mergeia dois sets + if (N > s.N) swap(*this, s); + expand(s.N); + root = merge(root, s.root, N+1); + s.root = NULL; + } + + node* split(node*& x, int k, T tam) { + if (k <= 0 or !x) return NULL; + prop(x, tam); + node* ret = new node(); + if (tam == 1) x->cnt = 0, ret->cnt = 1; + else { + if (k <= count(x->l, tam>>1)) ret->l = split(x->l, k, tam>>1); + else { + ret->r = split(x->r, k - count(x->l, tam>>1), tam>>1); + swap(x->l, ret->l); + } + ret->update(), x->update(); + } + return ret; + } + void split(int k, sms& s) { // pega os 'k' menores + s.clear(); + s.root = split(root, min(k, size()), N+1); + s.N = N; + } + // pega os menores que 'k' + void split_val(T k, sms& s) { split(order_of_key(k), s); } + + void flip(node*& at, T a, T b, T l, T r) { + if (!at) at = new node(); + else prop(at, r-l+1); + if (a <= l and r <= b) { + at->flip ^= 1; + prop(at, r-l+1); + return; + } + if (r < a or b < l) return; + T m = l + (r-l)/2; + flip(at->l, a, b, l, m), flip(at->r, a, b, m+1, r); + at->update(); + } + void flip(T l, T r) { // flipa os valores em [l, r] + assert(l >= 0 and l <= r); + expand(r); + flip(root, l, r, 0, N); + } + // complemento considerando que o universo eh [0, lim] + void complement(T lim) { + assert(lim >= 0); + if (lim > N) expand(lim); + flip(root, 0, lim, 0, N); + sms tmp; + split_val(lim+1, tmp); + swap(*this, tmp); + } + void insert_range(T l, T r) { // insere todo os valores em [l, r] + sms tmp; + tmp.flip(l, r); + merge(tmp); + } +}; +``` diff --git a/content/docs/Estruturas/sqrtTree.md b/content/docs/Estruturas/sqrtTree.md new file mode 100644 index 0000000..7edf8a6 --- /dev/null +++ b/content/docs/Estruturas/sqrtTree.md @@ -0,0 +1,68 @@ +--- +weight: 10 +title: "SQRT Tree" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + RMQ em O(log log n) com O(n log log n) pra buildar + + Funciona com qualquer operacao associativa + + Tao rapido quanto a sparse table, mas usa menos memoria + + (log log (1e9) < 5, entao a query eh praticamente O(1)) + + + + build - O(n log log n) + + query - O(log log n) + + + +Link original: [sqrtTree.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Estruturas/sqrtTree.cpp) + +## Código +```cpp +namespace sqrtTree { + int n, *v; + int pref[4][MAX], sulf[4][MAX], getl[4][MAX], entre[4][MAX], sz[4]; + + int op(int a, int b) { return min(a, b); } + inline int getblk(int p, int i) { return (i-getl[p][i])/sz[p]; } + void build(int p, int l, int r) { + if (l+1 >= r) return; + for (int i = l; i <= r; i++) getl[p][i] = l; + for (int L = l; L <= r; L += sz[p]) { + int R = min(L+sz[p]-1, r); + pref[p][L] = v[L], sulf[p][R] = v[R]; + for (int i = L+1; i <= R; i++) pref[p][i] = op(pref[p][i-1], v[i]); + for (int i = R-1; i >= L; i--) sulf[p][i] = op(v[i], sulf[p][i+1]); + build(p+1, L, R); + } + for (int i = 0; i <= sz[p]; i++) { + int at = entre[p][l+i*sz[p]+i] = sulf[p][l+i*sz[p]]; + for (int j = i+1; j <= sz[p]; j++) entre[p][l+i*sz[p]+j] = at = + op(at, sulf[p][l+j*sz[p]]); + } + } + void build(int n2, int* v2) { + n = n2, v = v2; + for (int p = 0; p < 4; p++) sz[p] = n2 = sqrt(n2); + build(0, 0, n-1); + } + int query(int l, int r) { + if (l+1 >= r) return l == r ? v[l] : op(v[l], v[r]); + int p = 0; + while (getblk(p, l) == getblk(p, r)) p++; + int ans = sulf[p][l], a = getblk(p, l)+1, b = getblk(p, r)-1; + if (a <= b) ans = op(ans, entre[p][getl[p][l]+a*sz[p]+b]); + return op(ans, pref[p][r]); + } +} +``` diff --git a/content/docs/Estruturas/treap.md b/content/docs/Estruturas/treap.md new file mode 100644 index 0000000..3965d2f --- /dev/null +++ b/content/docs/Estruturas/treap.md @@ -0,0 +1,131 @@ +--- +weight: 10 +title: "Treap" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Todas as operacoes custam + + O(log(n)) com alta probabilidade, exceto meld + + meld custa O(log^2 n) amortizado com alta prob., + + e permite unir duas treaps sem restricao adicional + + Na pratica, esse meld tem constante muito boa e + + o pior caso eh meio estranho de acontecer + + + +Link original: [treap.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Estruturas/treap.cpp) + +## Código +```cpp +mt19937 rng((int) chrono::steady_clock::now().time_since_epoch().count()); + +template struct treap { + struct node { + node *l, *r; + int p, sz; + T val, mi; + node(T v) : l(NULL), r(NULL), p(rng()), sz(1), val(v), mi(v) {} + void update() { + sz = 1; + mi = val; + if (l) sz += l->sz, mi = min(mi, l->mi); + if (r) sz += r->sz, mi = min(mi, r->mi); + } + }; + + node* root; + + treap() { root = NULL; } + treap(const treap& t) { + throw logic_error("Nao copiar a treap!"); + } + ~treap() { + vector q = {root}; + while (q.size()) { + node* x = q.back(); q.pop_back(); + if (!x) continue; + q.push_back(x->l), q.push_back(x->r); + delete x; + } + } + + int size(node* x) { return x ? x->sz : 0; } + int size() { return size(root); } + void join(node* l, node* r, node*& i) { // assume que l < r + if (!l or !r) return void(i = l ? l : r); + if (l->p > r->p) join(l->r, r, l->r), i = l; + else join(l, r->l, r->l), i = r; + i->update(); + } + void split(node* i, node*& l, node*& r, T v) { + if (!i) return void(r = l = NULL); + if (i->val < v) split(i->r, i->r, r, v), l = i; + else split(i->l, l, i->l, v), r = i; + i->update(); + } + void split_leq(node* i, node*& l, node*& r, T v) { + if (!i) return void(r = l = NULL); + if (i->val <= v) split_leq(i->r, i->r, r, v), l = i; + else split_leq(i->l, l, i->l, v), r = i; + i->update(); + } + int count(node* i, T v) { + if (!i) return 0; + if (i->val == v) return 1; + if (v < i->val) return count(i->l, v); + return count(i->r, v); + } + void index_split(node* i, node*& l, node*& r, int v, int key = 0) { + if (!i) return void(r = l = NULL); + if (key + size(i->l) < v) index_split(i->r, i->r, r, v, key+size(i->l)+1), l = i; + else index_split(i->l, l, i->l, v, key), r = i; + i->update(); + } + int count(T v) { + return count(root, v); + } + void insert(T v) { + if (count(v)) return; + node *L, *R; + split(root, L, R, v); + node* at = new node(v); + join(L, at, L); + join(L, R, root); + } + void erase(T v) { + node *L, *M, *R; + split_leq(root, M, R, v), split(M, L, M, v); + if (M) delete M; + M = NULL; + join(L, R, root); + } + void meld(treap& t) { // segmented merge + node *L = root, *R = t.root; + root = NULL; + while (L or R) { + if (!L or (L and R and L->mi > R->mi)) std::swap(L, R); + if (!R) join(root, L, root), L = NULL; + else if (L->mi == R->mi) { + node* LL; + split(L, LL, L, R->mi+1); + delete LL; + } else { + node* LL; + split(L, LL, L, R->mi); + join(root, LL, root); + } + } + t.root = NULL; + } +}; +``` diff --git a/content/docs/Estruturas/treapImplicita.md b/content/docs/Estruturas/treapImplicita.md new file mode 100644 index 0000000..d2af033 --- /dev/null +++ b/content/docs/Estruturas/treapImplicita.md @@ -0,0 +1,107 @@ +--- +weight: 10 +title: "Treap Implicita" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Todas as operacoes custam + + O(log(n)) com alta probabilidade + + + +Link original: [treapImplicita.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Estruturas/treapImplicita.cpp) + +## Código +```cpp +mt19937 rng((int) chrono::steady_clock::now().time_since_epoch().count()); + +template struct treap { + struct node { + node *l, *r; + int p, sz; + T val, sub, lazy; + bool rev; + node(T v) : l(NULL), r(NULL), p(rng()), sz(1), val(v), sub(v), lazy(0), rev(0) {} + void prop() { + if (lazy) { + val += lazy, sub += lazy*sz; + if (l) l->lazy += lazy; + if (r) r->lazy += lazy; + } + if (rev) { + swap(l, r); + if (l) l->rev ^= 1; + if (r) r->rev ^= 1; + } + lazy = 0, rev = 0; + } + void update() { + sz = 1, sub = val; + if (l) l->prop(), sz += l->sz, sub += l->sub; + if (r) r->prop(), sz += r->sz, sub += r->sub; + } + }; + + node* root; + + treap() { root = NULL; } + treap(const treap& t) { + throw logic_error("Nao copiar a treap!"); + } + ~treap() { + vector q = {root}; + while (q.size()) { + node* x = q.back(); q.pop_back(); + if (!x) continue; + q.push_back(x->l), q.push_back(x->r); + delete x; + } + } + + int size(node* x) { return x ? x->sz : 0; } + int size() { return size(root); } + void join(node* l, node* r, node*& i) { // assume que l < r + if (!l or !r) return void(i = l ? l : r); + l->prop(), r->prop(); + if (l->p > r->p) join(l->r, r, l->r), i = l; + else join(l, r->l, r->l), i = r; + i->update(); + } + void split(node* i, node*& l, node*& r, int v, int key = 0) { + if (!i) return void(r = l = NULL); + i->prop(); + if (key + size(i->l) < v) split(i->r, i->r, r, v, key+size(i->l)+1), l = i; + else split(i->l, l, i->l, v, key), r = i; + i->update(); + } + void push_back(T v) { + node* i = new node(v); + join(root, i, root); + } + T query(int l, int r) { + node *L, *M, *R; + split(root, M, R, r+1), split(M, L, M, l); + T ans = M->sub; + join(L, M, M), join(M, R, root); + return ans; + } + void update(int l, int r, T s) { + node *L, *M, *R; + split(root, M, R, r+1), split(M, L, M, l); + M->lazy += s; + join(L, M, M), join(M, R, root); + } + void reverse(int l, int r) { + node *L, *M, *R; + split(root, M, R, r+1), split(M, L, M, l); + M->rev ^= 1; + join(L, M, M), join(M, R, root); + } +}; +``` diff --git a/content/docs/Estruturas/treapPersistent.md b/content/docs/Estruturas/treapPersistent.md new file mode 100644 index 0000000..eca0ccc --- /dev/null +++ b/content/docs/Estruturas/treapPersistent.md @@ -0,0 +1,72 @@ +--- +weight: 10 +title: "Treap Persistent Implicita" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Todas as operacoes custam + + O(log(n)) com alta probabilidade + + + +Link original: [treapPersistent.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Estruturas/treapPersistent.cpp) + +## Código +```cpp +mt19937_64 rng((int) chrono::steady_clock::now().time_since_epoch().count()); + +struct node { + node *l, *r; + ll sz, val, sub; + node(ll v) : l(NULL), r(NULL), sz(1), val(v), sub(v) {} + node(node* x) : l(x->l), r(x->r), sz(x->sz), val(x->val), sub(x->sub) {} + void update() { + sz = 1, sub = val; + if (l) sz += l->sz, sub += l->sub; + if (r) sz += r->sz, sub += r->sub; + sub %= MOD; + } +}; + +ll size(node* x) { return x ? x->sz : 0; } +void update(node* x) { if (x) x->update(); } +node* copy(node* x) { return x ? new node(x) : NULL; } + +node* join(node* l, node* r) { + if (!l or !r) return l ? copy(l) : copy(r); + node* ret; + if (rng() % (size(l) + size(r)) < size(l)) { + ret = copy(l); + ret->r = join(ret->r, r); + } else { + ret = copy(r); + ret->l = join(l, ret->l); + } + return update(ret), ret; +} + +void split(node* x, node*& l, node*& r, ll v, ll key = 0) { + if (!x) return void(l = r = NULL); + if (key + size(x->l) < v) { + l = copy(x); + split(l->r, l->r, r, v, key+size(l->l)+1); + } else { + r = copy(x); + split(r->l, l, r->l, v, key); + } + update(l), update(r); +} + +vector treap; + +void init(const vector& v) { + treap = {NULL}; + for (auto i : v) treap[0] = join(treap[0], new node(i)); +} +``` diff --git a/content/docs/Estruturas/waveletTree.md b/content/docs/Estruturas/waveletTree.md new file mode 100644 index 0000000..5af5f8e --- /dev/null +++ b/content/docs/Estruturas/waveletTree.md @@ -0,0 +1,95 @@ +--- +weight: 10 +title: "Wavelet Tree" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Usa O(sigma + n log(sigma)) de memoria, + + onde sigma = MAXN - MINN + + Depois do build, o v fica ordenado + + count(i, j, x, y) retorna o numero de elementos de + + v[i, j) que pertencem a [x, y] + + kth(i, j, k) retorna o elemento que estaria + + na poscicao k-1 de v[i, j), se ele fosse ordenado + + sum(i, j, x, y) retorna a soma dos elementos de + + v[i, j) que pertencem a [x, y] + + sumk(i, j, k) retorna a soma dos k-esimos menores + + elementos de v[i, j) (sum(i, j, 1) retorna o menor) + + + + Complexidades: + + build - O(n log(sigma)) + + count - O(log(sigma)) + + kth - O(log(sigma)) + + sum - O(log(sigma)) + + sumk - O(log(sigma)) + + + +Link original: [waveletTree.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Estruturas/waveletTree.cpp) + +## Código +```cpp +int n, v[MAX]; +vector esq[4*(MAXN-MINN)], pref[4*(MAXN-MINN)]; + +void build(int b = 0, int e = n, int p = 1, int l = MINN, int r = MAXN) { + int m = (l+r)/2; esq[p].push_back(0); pref[p].push_back(0); + for (int i = b; i < e; i++) { + esq[p].push_back(esq[p].back()+(v[i]<=m)); + pref[p].push_back(pref[p].back()+v[i]); + } + if (l == r) return; + int m2 = stable_partition(v+b, v+e, [=](int i){return i <= m;}) - v; + build(b, m2, 2*p, l, m), build(m2, e, 2*p+1, m+1, r); +} + +int count(int i, int j, int x, int y, int p = 1, int l = MINN, int r = MAXN) { + if (y < l or r < x) return 0; + if (x <= l and r <= y) return j-i; + int m = (l+r)/2, ei = esq[p][i], ej = esq[p][j]; + return count(ei, ej, x, y, 2*p, l, m)+count(i-ei, j-ej, x, y, 2*p+1, m+1, r); +} + +int kth(int i, int j, int k, int p=1, int l = MINN, int r = MAXN) { + if (l == r) return l; + int m = (l+r)/2, ei = esq[p][i], ej = esq[p][j]; + if (k <= ej-ei) return kth(ei, ej, k, 2*p, l, m); + return kth(i-ei, j-ej, k-(ej-ei), 2*p+1, m+1, r); +} + +int sum(int i, int j, int x, int y, int p = 1, int l = MINN, int r = MAXN) { + if (y < l or r < x) return 0; + if (x <= l and r <= y) return pref[p][j]-pref[p][i]; + int m = (l+r)/2, ei = esq[p][i], ej = esq[p][j]; + return sum(ei, ej, x, y, 2*p, l, m) + sum(i-ei, j-ej, x, y, 2*p+1, m+1, r); +} + +int sumk(int i, int j, int k, int p = 1, int l = MINN, int r = MAXN) { + if (l == r) return l*k; + int m = (l+r)/2, ei = esq[p][i], ej = esq[p][j]; + if (k <= ej-ei) return sumk(ei, ej, k, 2*p, l, m); + return pref[2*p][ej]-pref[2*p][ei]+sumk(i-ei, j-ej, k-(ej-ei), 2*p+1, m+1, r); +} +``` diff --git a/content/docs/Extra/_index.md b/content/docs/Extra/_index.md new file mode 100644 index 0000000..54153de --- /dev/null +++ b/content/docs/Extra/_index.md @@ -0,0 +1,8 @@ +--- +weight: 10 +title: "Extra" +draft: false +date: "2024-05-09T17:19:25-0300" +description: "" +publishdate: "2024-05-09T17:19:25-0300" +--- diff --git a/content/docs/Grafos/_index.md b/content/docs/Grafos/_index.md new file mode 100644 index 0000000..c5ae2af --- /dev/null +++ b/content/docs/Grafos/_index.md @@ -0,0 +1,8 @@ +--- +weight: 10 +title: "Grafos" +draft: false +date: "2024-05-09T17:19:25-0300" +description: "" +publishdate: "2024-05-09T17:19:25-0300" +--- diff --git a/content/docs/Grafos/articulationPoints.md b/content/docs/Grafos/articulationPoints.md new file mode 100644 index 0000000..08e321e --- /dev/null +++ b/content/docs/Grafos/articulationPoints.md @@ -0,0 +1,64 @@ +--- +weight: 10 +title: "Articulation Points" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Computa os pontos de articulacao (vertices criticos) de um grafo + + + + art[i] armazena o numero de novas componentes criadas ao deletar vertice i + + se art[i] >= 1, entao vertice i eh ponto de articulacao + + + + O(n+m) + + + +Link original: [articulationPoints.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/articulationPoints.cpp) + +## Código +```cpp +int n; +vector> g; +stack s; +vector id, art; + +int dfs_art(int i, int& t, int p = -1) { + int lo = id[i] = t++; + s.push(i); + for (int j : g[i]) if (j != p) { + if (id[j] == -1) { + int val = dfs_art(j, t, i); + lo = min(lo, val); + + if (val >= id[i]) { + art[i]++; + while (s.top() != j) s.pop(); + s.pop(); + } + // if (val > id[i]) aresta i-j eh ponte + } + else lo = min(lo, id[j]); + } + if (p == -1 and art[i]) art[i]--; + return lo; +} + +void compute_art_points() { + id = vector(n, -1); + art = vector(n, 0); + int t = 0; + for (int i = 0; i < n; i++) if (id[i] == -1) + dfs_art(i, t, -1); +} + +``` diff --git a/content/docs/Grafos/bellmanFord.md b/content/docs/Grafos/bellmanFord.md new file mode 100644 index 0000000..e69f80e --- /dev/null +++ b/content/docs/Grafos/bellmanFord.md @@ -0,0 +1,54 @@ +--- +weight: 10 +title: "Bellman-Ford" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Calcula a menor distancia + + entre a e todos os vertices e + + detecta ciclo negativo + + Retorna 1 se ha ciclo negativo + + Nao precisa representar o grafo, + + soh armazenar as arestas + + + + O(nm) + + + +Link original: [bellmanFord.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/bellmanFord.cpp) + +## Código +```cpp +int n, m; +int d[MAX]; +vector> ar; // vetor de arestas +vector w; // peso das arestas + +bool bellman_ford(int a) { + for (int i = 0; i < n; i++) d[i] = INF; + d[a] = 0; + + for (int i = 0; i <= n; i++) + for (int j = 0; j < m; j++) { + if (d[ar[j].second] > d[ar[j].first] + w[j]) { + if (i == n) return 1; + + d[ar[j].second] = d[ar[j].first] + w[j]; + } + } + + return 0; +} +``` diff --git a/content/docs/Grafos/blockCutTree.md b/content/docs/Grafos/blockCutTree.md new file mode 100644 index 0000000..7398427 --- /dev/null +++ b/content/docs/Grafos/blockCutTree.md @@ -0,0 +1,116 @@ +--- +weight: 10 +title: "Block-Cut Tree" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Cria a block-cut tree, uma arvore com os blocos + + e os pontos de articulacao + + Blocos sao componentes 2-vertice-conexos maximais + + Uma 2-coloracao da arvore eh tal que uma cor sao + + os blocos, e a outra cor sao os pontos de art. + + Funciona para grafo nao conexo + + + + art[i] responde o numero de novas componentes conexas + + criadas apos a remocao de i do grafo g + + Se art[i] >= 1, i eh ponto de articulacao + + + + Para todo i <= blocks.size() + + blocks[i] eh uma componente 2-vertce-conexa maximal + + edgblocks[i] sao as arestas do bloco i + + tree[i] eh um vertice da arvore que corresponde ao bloco i + + + + pos[i] responde a qual vertice da arvore vertice i pertence + + Arvore tem no maximo 2n vertices + + + + O(n+m) + + + +Link original: [blockCutTree.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/blockCutTree.cpp) + +## Código +```cpp +struct block_cut_tree { + vector> g, blocks, tree; + vector>> edgblocks; + stack s; + stack> s2; + vector id, art, pos; + + block_cut_tree(vector> g_) : g(g_) { + int n = g.size(); + id.resize(n, -1), art.resize(n), pos.resize(n); + build(); + } + + int dfs(int i, int& t, int p = -1) { + int lo = id[i] = t++; + s.push(i); + + if (p != -1) s2.emplace(i, p); + for (int j : g[i]) if (j != p and id[j] != -1) s2.emplace(i, j); + + for (int j : g[i]) if (j != p) { + if (id[j] == -1) { + int val = dfs(j, t, i); + lo = min(lo, val); + + if (val >= id[i]) { + art[i]++; + blocks.emplace_back(1, i); + while (blocks.back().back() != j) + blocks.back().push_back(s.top()), s.pop(); + + edgblocks.emplace_back(1, s2.top()), s2.pop(); + while (edgblocks.back().back() != pair(j, i)) + edgblocks.back().push_back(s2.top()), s2.pop(); + } + // if (val > id[i]) aresta i-j eh ponte + } + else lo = min(lo, id[j]); + } + + if (p == -1 and art[i]) art[i]--; + return lo; + } + + void build() { + int t = 0; + for (int i = 0; i < g.size(); i++) if (id[i] == -1) dfs(i, t, -1); + + tree.resize(blocks.size()); + for (int i = 0; i < g.size(); i++) if (art[i]) + pos[i] = tree.size(), tree.emplace_back(); + + for (int i = 0; i < blocks.size(); i++) for (int j : blocks[i]) { + if (!art[j]) pos[j] = i; + else tree[i].push_back(pos[j]), tree[pos[j]].push_back(i); + } + } +}; +``` diff --git a/content/docs/Grafos/blossom.md b/content/docs/Grafos/blossom.md new file mode 100644 index 0000000..460db1e --- /dev/null +++ b/content/docs/Grafos/blossom.md @@ -0,0 +1,105 @@ +--- +weight: 10 +title: "Blossom" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Matching maximo em grafo geral + + + + O(n^3) + + Se for bipartido, nao precisa da funcao + + 'contract', e roda em O(nm) + + + +Link original: [blossom.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/blossom.cpp) + +## Código +```cpp +vector g[MAX]; +int match[MAX]; // match[i] = com quem i esta matchzado ou -1 +int n, pai[MAX], base[MAX], vis[MAX]; +queue q; + +void contract(int u, int v, bool first = 1) { + static vector bloss; + static int l; + if (first) { + bloss = vector(n, 0); + vector teve(n, 0); + int k = u; l = v; + while (1) { + teve[k = base[k]] = 1; + if (match[k] == -1) break; + k = pai[match[k]]; + } + while (!teve[l = base[l]]) l = pai[match[l]]; + } + while (base[u] != l) { + bloss[base[u]] = bloss[base[match[u]]] = 1; + pai[u] = v; + v = match[u]; + u = pai[match[u]]; + } + if (!first) return; + contract(v, u, 0); + for (int i = 0; i < n; i++) if (bloss[base[i]]) { + base[i] = l; + if (!vis[i]) q.push(i); + vis[i] = 1; + } +} + +int getpath(int s) { + for (int i = 0; i < n; i++) base[i] = i, pai[i] = -1, vis[i] = 0; + vis[s] = 1; q = queue(); q.push(s); + while (q.size()) { + int u = q.front(); q.pop(); + for (int i : g[u]) { + if (base[i] == base[u] or match[u] == i) continue; + if (i == s or (match[i] != -1 and pai[match[i]] != -1)) + contract(u, i); + else if (pai[i] == -1) { + pai[i] = u; + if (match[i] == -1) return i; + i = match[i]; + vis[i] = 1; q.push(i); + } + } + } + return -1; +} + +int blossom() { + int ans = 0; + memset(match, -1, sizeof(match)); + for (int i = 0; i < n; i++) if (match[i] == -1) + for (int j : g[i]) if (match[j] == -1) { + match[i] = j; + match[j] = i; + ans++; + break; + } + for (int i = 0; i < n; i++) if (match[i] == -1) { + int j = getpath(i); + if (j == -1) continue; + ans++; + while (j != -1) { + int p = pai[j], pp = match[p]; + match[p] = j; + match[j] = p; + j = pp; + } + } + return ans; +} +``` diff --git a/content/docs/Grafos/center.md b/content/docs/Grafos/center.md new file mode 100644 index 0000000..f90f3f8 --- /dev/null +++ b/content/docs/Grafos/center.md @@ -0,0 +1,51 @@ +--- +weight: 10 +title: "Centro de arvore" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Retorna o diametro e o(s) centro(s) da arvore + + Uma arvore tem sempre um ou dois centros e estes estao no meio do diametro + + + + O(n) + + + +Link original: [center.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/center.cpp) + +## Código +```cpp +vector g[MAX]; +int d[MAX], par[MAX]; + +pair> center() { + int f, df; + function dfs = [&] (int v) { + if (d[v] > df) f = v, df = d[v]; + for (int u : g[v]) if (u != par[v]) + d[u] = d[v] + 1, par[u] = v, dfs(u); + }; + + f = df = par[0] = -1, d[0] = 0; + dfs(0); + int root = f; + f = df = par[root] = -1, d[root] = 0; + dfs(root); + + vector c; + while (f != -1) { + if (d[f] == df/2 or d[f] == (df+1)/2) c.push_back(f); + f = par[f]; + } + + return {df, c}; +} +``` diff --git a/content/docs/Grafos/centroid.md b/content/docs/Grafos/centroid.md new file mode 100644 index 0000000..932758c --- /dev/null +++ b/content/docs/Grafos/centroid.md @@ -0,0 +1,48 @@ +--- +weight: 10 +title: "Centroid" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Computa os 2 centroids da arvore + + + + O(n) + + + +Link original: [centroid.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/centroid.cpp) + +## Código +```cpp +int n, subsize[MAX]; +vector g[MAX]; + +void dfs(int k, int p=-1) { + subsize[k] = 1; + for (int i : g[k]) if (i != p) { + dfs(i, k); + subsize[k] += subsize[i]; + } +} + +int centroid(int k, int p=-1, int size=-1) { + if (size == -1) size = subsize[k]; + for (int i : g[k]) if (i != p) if (subsize[i] > size/2) + return centroid(i, k, size); + return k; +} + +pair centroids(int k=0) { + dfs(k); + int i = centroid(k), i2 = i; + for (int j : g[i]) if (2*subsize[j] == subsize[k]) i2 = j; + return {i, i2}; +} +``` diff --git a/content/docs/Grafos/centroidDecomp.md b/content/docs/Grafos/centroidDecomp.md new file mode 100644 index 0000000..6f536a2 --- /dev/null +++ b/content/docs/Grafos/centroidDecomp.md @@ -0,0 +1,66 @@ +--- +weight: 10 +title: "Centroid decomposition" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + decomp(0, k) computa numero de caminhos com 'k' arestas + + Mudar depois do comentario + + + + O(n log(n)) + + + +Link original: [centroidDecomp.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/centroidDecomp.cpp) + +## Código +```cpp +vector g[MAX]; +int sz[MAX], rem[MAX]; + +void dfs(vector& path, int i, int l=-1, int d=0) { + path.push_back(d); + for (int j : g[i]) if (j != l and !rem[j]) dfs(path, j, i, d+1); +} + +int dfs_sz(int i, int l=-1) { + sz[i] = 1; + for (int j : g[i]) if (j != l and !rem[j]) sz[i] += dfs_sz(j, i); + return sz[i]; +} + +int centroid(int i, int l, int size) { + for (int j : g[i]) if (j != l and !rem[j] and sz[j] > size / 2) + return centroid(j, i, size); + return i; +} + +ll decomp(int i, int k) { + int c = centroid(i, i, dfs_sz(i)); + rem[c] = 1; + + // gasta O(n) aqui - dfs sem ir pros caras removidos + ll ans = 0; + vector cnt(sz[i]); + cnt[0] = 1; + for (int j : g[c]) if (!rem[j]) { + vector path; + dfs(path, j); + for (int d : path) if (0 <= k-d-1 and k-d-1 < sz[i]) + ans += cnt[k-d-1]; + for (int d : path) cnt[d+1]++; + } + + for (int j : g[c]) if (!rem[j]) ans += decomp(j, k); + rem[c] = 0; + return ans; +} +``` diff --git a/content/docs/Grafos/centroidTree.md b/content/docs/Grafos/centroidTree.md new file mode 100644 index 0000000..36875ca --- /dev/null +++ b/content/docs/Grafos/centroidTree.md @@ -0,0 +1,63 @@ +--- +weight: 10 +title: "Centroid Tree" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Constroi a centroid tree + + p[i] eh o pai de i na centroid-tree + + dist[i][k] = distancia na arvore original entre i + + e o k-esimo ancestral na arvore da centroid + + + + O(n log(n)) de tempo e memoria + + + +Link original: [centroidTree.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/centroidTree.cpp) + +## Código +```cpp +vector g[MAX], dist[MAX]; +int sz[MAX], rem[MAX], p[MAX]; + +int dfs_sz(int i, int l=-1) { + sz[i] = 1; + for (int j : g[i]) if (j != l and !rem[j]) sz[i] += dfs_sz(j, i); + return sz[i]; +} + +int centroid(int i, int l, int size) { + for (int j : g[i]) if (j != l and !rem[j] and sz[j] > size / 2) + return centroid(j, i, size); + return i; +} + +void dfs_dist(int i, int l, int d=0) { + dist[i].push_back(d); + for (int j : g[i]) if (j != l and !rem[j]) + dfs_dist(j, i, d+1); +} + +void decomp(int i, int l = -1) { + int c = centroid(i, i, dfs_sz(i)); + rem[c] = 1, p[c] = l; + dfs_dist(c, c); + for (int j : g[c]) if (!rem[j]) decomp(j, c); +} + +void build(int n) { + for (int i = 0; i < n; i++) rem[i] = 0, dist[i].clear(); + decomp(0); + for (int i = 0; i < n; i++) reverse(dist[i].begin(), dist[i].end()); +} +``` diff --git a/content/docs/Grafos/cover.md b/content/docs/Grafos/cover.md new file mode 100644 index 0000000..eb33242 --- /dev/null +++ b/content/docs/Grafos/cover.md @@ -0,0 +1,77 @@ +--- +weight: 10 +title: "Vertex cover" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Encontra o tamanho do vertex cover minimo + + Da pra alterar facil pra achar os vertices + + Parece rodar com < 2 s pra N = 90 + + + + O(n * 1.38^n) + + + +Link original: [cover.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/cover.cpp) + +## Código +```cpp +namespace cover { + const int MAX = 96; + vector g[MAX]; + bitset bs[MAX]; + int n; + + void add(int i, int j) { + if (i == j) return; + n = max({n, i+1, j+1}); + bs[i][j] = bs[j][i] = 1; + } + + int rec(bitset m) { + int ans = 0; + for (int x = 0; x < n; x++) if (m[x]) { + bitset comp; + function dfs = [&](int i) { + comp[i] = 1, m[i] = 0; + for (int j : g[i]) if (m[j]) dfs(j); + }; + dfs(x); + + int ma, deg = -1, cyc = 1; + for (int i = 0; i < n; i++) if (comp[i]) { + int d = (bs[i]&comp).count(); + if (d <= 1) cyc = 0; + if (d > deg) deg = d, ma = i; + } + if (deg <= 2) { // caminho ou ciclo + ans += (comp.count() + cyc) / 2; + continue; + } + comp[ma] = 0; + + // ou ta no cover, ou nao ta no cover + ans += min(1 + rec(comp), deg + rec(comp & ~bs[ma])); + } + return ans; + } + int solve() { + bitset m; + for (int i = 0; i < n; i++) { + m[i] = 1; + for (int j = 0; j < n; j++) + if (bs[i][j]) g[i].push_back(j); + } + return rec(m); + } +} +``` diff --git a/content/docs/Grafos/dijkstra.md b/content/docs/Grafos/dijkstra.md new file mode 100644 index 0000000..74a5a7a --- /dev/null +++ b/content/docs/Grafos/dijkstra.md @@ -0,0 +1,51 @@ +--- +weight: 10 +title: "Dijkstra" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + encontra menor distancia de x + + para todos os vertices + + se ao final do algoritmo d[i] = LINF, + + entao x nao alcanca i + + + + O(m log(n)) + + + +Link original: [dijkstra.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/dijkstra.cpp) + +## Código +```cpp +ll d[MAX]; +vector> g[MAX]; // {vizinho, peso} + +int n; + +void dijkstra(int v) { + for (int i = 0; i < n; i++) d[i] = LINF; + d[v] = 0; + priority_queue> pq; + pq.emplace(0, v); + + while (pq.size()) { + auto [ndist, u] = pq.top(); pq.pop(); + if (-ndist > d[u]) continue; + + for (auto [idx, w] : g[u]) if (d[idx] > d[u] + w) { + d[idx] = d[u] + w; + pq.emplace(-d[idx], idx); + } + } +} +``` diff --git a/content/docs/Grafos/dinitz.md b/content/docs/Grafos/dinitz.md new file mode 100644 index 0000000..57a8d81 --- /dev/null +++ b/content/docs/Grafos/dinitz.md @@ -0,0 +1,92 @@ +--- +weight: 10 +title: "Dinitz" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + O(min(m * max_flow, n^2 m)) + + Grafo com capacidades 1: O(min(m sqrt(m), m * n^(2/3))) + + Todo vertice tem grau de entrada ou saida 1: O(m sqrt(n)) + + + +Link original: [dinitz.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/dinitz.cpp) + +## Código +```cpp +struct dinitz { + const bool scaling = false; // com scaling -> O(nm log(MAXCAP)), + int lim; // com constante alta + struct edge { + int to, cap, rev, flow; + bool res; + edge(int to_, int cap_, int rev_, bool res_) + : to(to_), cap(cap_), rev(rev_), flow(0), res(res_) {} + }; + + vector> g; + vector lev, beg; + ll F; + dinitz(int n) : g(n), F(0) {} + + void add(int a, int b, int c) { + g[a].emplace_back(b, c, g[b].size(), false); + g[b].emplace_back(a, 0, g[a].size()-1, true); + } + bool bfs(int s, int t) { + lev = vector(g.size(), -1); lev[s] = 0; + beg = vector(g.size(), 0); + queue q; q.push(s); + while (q.size()) { + int u = q.front(); q.pop(); + for (auto& i : g[u]) { + if (lev[i.to] != -1 or (i.flow == i.cap)) continue; + if (scaling and i.cap - i.flow < lim) continue; + lev[i.to] = lev[u] + 1; + q.push(i.to); + } + } + return lev[t] != -1; + } + int dfs(int v, int s, int f = INF) { + if (!f or v == s) return f; + for (int& i = beg[v]; i < g[v].size(); i++) { + auto& e = g[v][i]; + if (lev[e.to] != lev[v] + 1) continue; + int foi = dfs(e.to, s, min(f, e.cap - e.flow)); + if (!foi) continue; + e.flow += foi, g[e.to][e.rev].flow -= foi; + return foi; + } + return 0; + } + ll max_flow(int s, int t) { + for (lim = scaling ? (1<<30) : 1; lim; lim /= 2) + while (bfs(s, t)) while (int ff = dfs(s, t)) F += ff; + return F; + } +}; + +// Recupera as arestas do corte s-t +vector> get_cut(dinitz& g, int s, int t) { + g.max_flow(s, t); + vector> cut; + vector vis(g.g.size(), 0), st = {s}; + vis[s] = 1; + while (st.size()) { + int u = st.back(); st.pop_back(); + for (auto e : g.g[u]) if (!vis[e.to] and e.flow < e.cap) + vis[e.to] = 1, st.push_back(e.to); + } + for (int i = 0; i < g.g.size(); i++) for (auto e : g.g[i]) + if (vis[i] and !vis[e.to] and !e.res) cut.emplace_back(i, e.to); + return cut; +} +``` diff --git a/content/docs/Grafos/directedMst.md b/content/docs/Grafos/directedMst.md new file mode 100644 index 0000000..9f60f23 --- /dev/null +++ b/content/docs/Grafos/directedMst.md @@ -0,0 +1,91 @@ +--- +weight: 10 +title: "AGM Direcionada" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Fala o menor custo para selecionar arestas tal que + + o vertice 'r' alcance todos + + Se nao tem como, retorna LINF + + + + O(m log(n)) + + + +Link original: [directedMst.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/directedMst.cpp) + +## Código +```cpp +struct node { + pair val; + ll lazy; + node *l, *r; + node() {} + node(pair v) : val(v), lazy(0), l(NULL), r(NULL) {} + + void prop() { + val.first += lazy; + if (l) l->lazy += lazy; + if (r) r->lazy += lazy; + lazy = 0; + } +}; +void merge(node*& a, node* b) { + if (!a) swap(a, b); + if (!b) return; + a->prop(), b->prop(); + if (a->val > b->val) swap(a, b); + merge(rand()%2 ? a->l : a->r, b); +} +pair pop(node*& R) { + R->prop(); + auto ret = R->val; + node* tmp = R; + merge(R->l, R->r); + R = R->l; + if (R) R->lazy -= ret.first; + delete tmp; + return ret; +} +void apaga(node* R) { if (R) apaga(R->l), apaga(R->r), delete R; } + +ll dmst(int n, int r, vector, int>>& ar) { + vector p(n); iota(p.begin(), p.end(), 0); + function find = [&](int k) { return p[k]==k?k:p[k]=find(p[k]); }; + vector h(n); + for (auto e : ar) merge(h[e.first.second], new node({e.second, e.first.first})); + vector pai(n, -1), path(n); + pai[r] = r; + ll ans = 0; + + for (int i = 0; i < n; i++) { // vai conectando todo mundo + int u = i, at = 0; + while (pai[u] == -1) { + if (!h[u]) { // nao tem + for (auto i : h) apaga(i); + return LINF; + } + path[at++] = u, pai[u] = i; + auto [mi, v] = pop(h[u]); + ans += mi; + + if (pai[u = find(v)] == i) { // ciclo + while (find(v = path[--at]) != u) + merge(h[u], h[v]), h[v] = NULL, p[find(v)] = u; + pai[u] = -1; + } + } + } + for (auto i : h) apaga(i); + return ans; +} +``` diff --git a/content/docs/Grafos/dominatorTree.md b/content/docs/Grafos/dominatorTree.md new file mode 100644 index 0000000..6591e08 --- /dev/null +++ b/content/docs/Grafos/dominatorTree.md @@ -0,0 +1,107 @@ +--- +weight: 10 +title: "Dominator Tree" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Codigo do Kawakami. Se vira pra usar ai + + + + build - O(m log(n)) + + dominates - O(1) + + + +Link original: [dominatorTree.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/dominatorTree.cpp) + +## Código +```cpp +int n; + +namespace d_tree { + vector g[MAX]; + + // The dominator tree + vector tree[MAX]; + int dfs_l[MAX], dfs_r[MAX]; + + // Auxiliary data + vector rg[MAX], bucket[MAX]; + int idom[MAX], sdom[MAX], prv[MAX], pre[MAX]; + int ancestor[MAX], label[MAX]; + vector preorder; + + void dfs(int v) { + static int t = 0; + pre[v] = ++t; + sdom[v] = label[v] = v; + preorder.push_back(v); + for (int nxt: g[v]) { + if (sdom[nxt] == -1) { + prv[nxt] = v; + dfs(nxt); + } + rg[nxt].push_back(v); + } + } + int eval(int v) { + if (ancestor[v] == -1) return v; + if (ancestor[ancestor[v]] == -1) return label[v]; + int u = eval(ancestor[v]); + if (pre[sdom[u]] < pre[sdom[label[v]]]) label[v] = u; + ancestor[v] = ancestor[u]; + return label[v]; + } + void dfs2(int v) { + static int t = 0; + dfs_l[v] = t++; + for (int nxt: tree[v]) dfs2(nxt); + dfs_r[v] = t++; + } + void build(int s) { + for (int i = 0; i < n; i++) { + sdom[i] = pre[i] = ancestor[i] = -1; + rg[i].clear(); + tree[i].clear(); + bucket[i].clear(); + } + preorder.clear(); + dfs(s); + if (preorder.size() == 1) return; + for (int i = int(preorder.size()) - 1; i >= 1; i--) { + int w = preorder[i]; + for (int v: rg[w]) { + int u = eval(v); + if (pre[sdom[u]] < pre[sdom[w]]) sdom[w] = sdom[u]; + } + bucket[sdom[w]].push_back(w); + ancestor[w] = prv[w]; + for (int v: bucket[prv[w]]) { + int u = eval(v); + idom[v] = (u == v) ? sdom[v] : u; + } + bucket[prv[w]].clear(); + } + for (int i = 1; i < preorder.size(); i++) { + int w = preorder[i]; + if (idom[w] != sdom[w]) idom[w] = idom[idom[w]]; + tree[idom[w]].push_back(w); + } + idom[s] = sdom[s] = -1; + dfs2(s); + } + + // Whether every path from s to v passes through u + bool dominates(int u, int v) { + if (pre[v] == -1) return 1; // vacuously true + return dfs_l[u] <= dfs_l[v] && dfs_r[v] <= dfs_r[u]; + } +}; +``` diff --git a/content/docs/Grafos/eulerPath.md b/content/docs/Grafos/eulerPath.md new file mode 100644 index 0000000..d2be1a7 --- /dev/null +++ b/content/docs/Grafos/eulerPath.md @@ -0,0 +1,98 @@ +--- +weight: 10 +title: "Euler Path / Euler Cycle" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Para declarar: 'euler E(n);' se quiser + + direcionado e com 'n' vertices + + As funcoes retornam um par com um booleano + + indicando se possui o cycle/path que voce pediu, + + e um vector de {vertice, id da aresta para chegar no vertice} + + Se for get_path, na primeira posicao o id vai ser -1 + + get_path(src) tenta achar um caminho ou ciclo euleriano + + comecando no vertice 'src'. + + Se achar um ciclo, o primeiro e ultimo vertice serao 'src'. + + Se for um P3, um possiveo retorno seria [0, 1, 2, 0] + + get_cycle() acha um ciclo euleriano se o grafo for euleriano. + + Se for um P3, um possivel retorno seria [0, 1, 2] + + (vertie inicial nao repete) + + + + O(n+m) + + + +Link original: [eulerPath.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/eulerPath.cpp) + +## Código +```cpp +template struct euler { + int n; + vector>> g; + vector used; + + euler(int n_) : n(n_), g(n) {} + void add(int a, int b) { + int at = used.size(); + used.push_back(0); + g[a].emplace_back(b, at); + if (!directed) g[b].emplace_back(a, at); + } +#warning chamar para o src certo! + pair>> get_path(int src) { + if (!used.size()) return {true, {}}; + vector beg(n, 0); + for (int& i : used) i = 0; + // {{vertice, anterior}, label} + vector, int>> ret, st = {{{src, -1}, -1}}; + while (st.size()) { + int at = st.back().first.first; + int& it = beg[at]; + while (it < g[at].size() and used[g[at][it].second]) it++; + if (it == g[at].size()) { + if (ret.size() and ret.back().first.second != at) + return {false, {}}; + ret.push_back(st.back()), st.pop_back(); + } else { + st.push_back({{g[at][it].first, at}, g[at][it].second}); + used[g[at][it].second] = 1; + } + } + if (ret.size() != used.size()+1) return {false, {}}; + vector> ans; + for (auto i : ret) ans.emplace_back(i.first.first, i.second); + reverse(ans.begin(), ans.end()); + return {true, ans}; + } + pair>> get_cycle() { + if (!used.size()) return {true, {}}; + int src = 0; + while (!g[src].size()) src++; + auto ans = get_path(src); + if (!ans.first or ans.second[0].first != ans.second.back().first) + return {false, {}}; + ans.second[0].second = ans.second.back().second; + ans.second.pop_back(); + return ans; + } +}; +``` diff --git a/content/docs/Grafos/eulerTourTree.md b/content/docs/Grafos/eulerTourTree.md new file mode 100644 index 0000000..a5080a3 --- /dev/null +++ b/content/docs/Grafos/eulerTourTree.md @@ -0,0 +1,211 @@ +--- +weight: 10 +title: "Euler Tour Tree" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Mantem uma floresta enraizada dinamicamente + + e permite queries/updates em sub-arvore + + + + Chamar ETT E(n, v), passando n = numero de vertices + + e v = vector com os valores de cada vertice (se for vazio, + + constroi tudo com 0 + + + + link(v, u) cria uma aresta de v pra u, de forma que u se torna + + o pai de v (eh preciso que v seja raiz anteriormente) + + cut(v) corta a resta de v para o pai + + query(v) retorna a soma dos valores da sub-arvore de v + + update(v, val) soma val em todos os vertices da sub-arvore de v + + update_v(v, val) muda o valor do vertice v para val + + is_in_subtree(v, u) responde se o vertice u esta na sub-arvore de v + + + + Tudo O(log(n)) com alta probabilidade + + + +Link original: [eulerTourTree.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/eulerTourTree.cpp) + +## Código +```cpp +mt19937 rng((int) chrono::steady_clock::now().time_since_epoch().count()); + +template struct ETT { + // treap + struct node { + node *l, *r, *p; + int pr, sz; + T val, sub, lazy; + int id; + bool f; // se eh o 'first' + int qt_f; // numero de firsts na subarvore + node(int id_, T v, bool f_ = 0) : l(NULL), r(NULL), p(NULL), pr(rng()), + sz(1), val(v), sub(v), lazy(), id(id_), f(f_), qt_f(f_) {} + void prop() { + if (lazy != T()) { + if (f) val += lazy; + sub += lazy*sz; + if (l) l->lazy += lazy; + if (r) r->lazy += lazy; + } + lazy = T(); + } + void update() { + sz = 1, sub = val, qt_f = f; + if (l) l->prop(), sz += l->sz, sub += l->sub, qt_f += l->qt_f; + if (r) r->prop(), sz += r->sz, sub += r->sub, qt_f += r->qt_f; + } + }; + + node* root; + + int size(node* x) { return x ? x->sz : 0; } + void join(node* l, node* r, node*& i) { // assume que l < r + if (!l or !r) return void(i = l ? l : r); + l->prop(), r->prop(); + if (l->pr > r->pr) join(l->r, r, l->r), l->r->p = i = l; + else join(l, r->l, r->l), r->l->p = i = r; + i->update(); + } + void split(node* i, node*& l, node*& r, int v, int key = 0) { + if (!i) return void(r = l = NULL); + i->prop(); + if (key + size(i->l) < v) { + split(i->r, i->r, r, v, key+size(i->l)+1), l = i; + if (r) r->p = NULL; + if (i->r) i->r->p = i; + } else { + split(i->l, l, i->l, v, key), r = i; + if (l) l->p = NULL; + if (i->l) i->l->p = i; + } + i->update(); + } + int get_idx(node* i) { + int ret = size(i->l); + for (; i->p; i = i->p) { + node* pai = i->p; + if (i != pai->l) ret += size(pai->l) + 1; + } + return ret; + } + node* get_min(node* i) { + if (!i) return NULL; + return i->l ? get_min(i->l) : i; + } + node* get_max(node* i) { + if (!i) return NULL; + return i->r ? get_max(i->r) : i; + } + // fim da treap + + vector first, last; + + ETT(int n, vector v = {}) : root(NULL), first(n), last(n) { + if (!v.size()) v = vector(n); + for (int i = 0; i < n; i++) { + first[i] = last[i] = new node(i, v[i], 1); + join(root, first[i], root); + } + } + ETT(const ETT& t) { throw logic_error("Nao copiar a ETT!"); } + ~ETT() { + vector q = {root}; + while (q.size()) { + node* x = q.back(); q.pop_back(); + if (!x) continue; + q.push_back(x->l), q.push_back(x->r); + delete x; + } + } + + pair get_range(int i) { + return {get_idx(first[i]), get_idx(last[i])}; + } + void link(int v, int u) { // 'v' tem que ser raiz + auto [lv, rv] = get_range(v); + int ru = get_idx(last[u]); + + node* V; + node *L, *M, *R; + split(root, M, R, rv+1), split(M, L, M, lv); + V = M; + join(L, R, root); + + split(root, L, R, ru+1); + join(L, V, L); + join(L, last[u] = new node(u, T() /* elemento neutro */), L); + join(L, R, root); + } + void cut(int v) { + auto [l, r] = get_range(v); + + node *L, *M, *R; + split(root, M, R, r+1), split(M, L, M, l); + node *LL = get_max(L), *RR = get_min(R); + if (LL and RR and LL->id == RR->id) { // remove duplicata + if (last[RR->id] == RR) last[RR->id] = LL; + node *A, *B; + split(R, A, B, 1); + delete A; + R = B; + } + join(L, R, root); + join(root, M, root); + } + T query(int v) { + auto [l, r] = get_range(v); + node *L, *M, *R; + split(root, M, R, r+1), split(M, L, M, l); + T ans = M->sub; + join(L, M, M), join(M, R, root); + return ans; + } + void update(int v, T val) { // soma val em todo mundo da subarvore + auto [l, r] = get_range(v); + node *L, *M, *R; + split(root, M, R, r+1), split(M, L, M, l); + M->lazy += val; + join(L, M, M), join(M, R, root); + } + void update_v(int v, T val) { // muda o valor de v pra val + int l = get_idx(first[v]); + node *L, *M, *R; + split(root, M, R, l+1), split(M, L, M, l); + M->val = M->sub = val; + join(L, M, M), join(M, R, root); + } + bool is_in_subtree(int v, int u) { // se u ta na subtree de v + auto [lv, rv] = get_range(v); + auto [lu, ru] = get_range(u); + return lv <= lu and ru <= rv; + } + + void print(node* i) { + if (!i) return; + print(i->l); + cout << i->id+1 << " "; + print(i->r); + } + void print() { print(root); cout << endl; } +}; +``` diff --git a/content/docs/Grafos/floydWarshall.md b/content/docs/Grafos/floydWarshall.md new file mode 100644 index 0000000..2cd0ece --- /dev/null +++ b/content/docs/Grafos/floydWarshall.md @@ -0,0 +1,48 @@ +--- +weight: 10 +title: "Floyd-Warshall" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + encontra o menor caminho entre todo + + par de vertices e detecta ciclo negativo + + returna 1 sse ha ciclo negativo + + d[i][i] deve ser 0 + + para i != j, d[i][j] deve ser w se ha uma aresta + + (i, j) de peso w, INF caso contrario + + + + O(n^3) + + + +Link original: [floydWarshall.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/floydWarshall.cpp) + +## Código +```cpp +int n; +int d[MAX][MAX]; + +bool floyd_warshall() { + for (int k = 0; k < n; k++) + for (int i = 0; i < n; i++) + for (int j = 0; j < n; j++) + d[i][j] = min(d[i][j], d[i][k] + d[k][j]); + + for (int i = 0; i < n; i++) + if (d[i][i] < 0) return 1; + + return 0; +} +``` diff --git a/content/docs/Grafos/functionalGraph.md b/content/docs/Grafos/functionalGraph.md new file mode 100644 index 0000000..37b78c8 --- /dev/null +++ b/content/docs/Grafos/functionalGraph.md @@ -0,0 +1,134 @@ +--- +weight: 10 +title: "Functional Graph" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + rt[i] fala o ID da raiz associada ao vertice i + + d[i] fala a profundidade (0 sse ta no ciclo) + + pos[i] fala a posicao de i no array que eh a concat. dos ciclos + + build(f, val) recebe a funcao f e o custo de ir de + + i para f[i] (por default, val = f) + + f_k(i, k) fala onde i vai parar se seguir k arestas + + path(i, k) fala o custo (soma) seguir k arestas a partir de i + + Se quiser outra operacao, da pra alterar facil o codigo + + Codigo um pouco louco, tenho que admitir + + + + build - O(n) + + f_k - O(log(min(n, k))) + + path - O(log(min(n, k))) + + + +Link original: [functionalGraph.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/functionalGraph.cpp) + +## Código +```cpp +namespace func_graph { + int n; + int f[MAX], vis[MAX], d[MAX]; + int p[MAX], pp[MAX], rt[MAX], pos[MAX]; + int sz[MAX], comp; + vector> ciclo; + ll val[MAX], jmp[MAX], seg[2*MAX]; + + ll op(ll a, ll b) { return a+b; }; // mudar a operacao aqui + void dfs(int i, int t = 2) { + vis[i] = t; + if (vis[f[i]] >= 2) { // comeca ciclo - f[i] eh o rep. + d[i] = 0, rt[i] = comp; + sz[comp] = t - vis[f[i]] + 1; + p[i] = pp[i] = i, jmp[i] = val[i]; + ciclo.emplace_back(); + ciclo.back().push_back(i); + } else { + if (!vis[f[i]]) dfs(f[i], t+1); + rt[i] = rt[f[i]]; + if (sz[comp]+1) { // to no ciclo + d[i] = 0; + p[i] = pp[i] = i, jmp[i] = val[i]; + ciclo.back().push_back(i); + } else { // nao to no ciclo + d[i] = d[f[i]]+1, p[i] = f[i]; + pp[i] = 2*d[pp[f[i]]] == d[pp[pp[f[i]]]]+d[f[i]] ? pp[pp[f[i]]] : f[i]; + jmp[i] = pp[i] == f[i] ? val[i] : op(val[i], op(jmp[f[i]], jmp[pp[f[i]]])); + } + } + if (f[ciclo[rt[i]][0]] == i) comp++; // fim do ciclo + vis[i] = 1; + } + void build(vector f_, vector val_ = {}) { + n = f_.size(), comp = 0; + if (!val_.size()) val_ = f_; + for (int i = 0; i < n; i++) + f[i] = f_[i], val[i] = val_[i], vis[i] = 0, sz[i] = -1; + + ciclo.clear(); + for (int i = 0; i < n; i++) if (!vis[i]) dfs(i); + int t = 0; + for (auto& c : ciclo) { + reverse(c.begin(), c.end()); + for (int j : c) { + pos[j] = t; + seg[n+t] = val[j]; + t++; + } + } + for (int i = n-1; i; i--) seg[i] = op(seg[2*i], seg[2*i+1]); + } + + int f_k(int i, ll k) { + while (d[i] and k) { + int big = d[i] - d[pp[i]]; + if (big <= k) k -= big, i = pp[i]; + else k--, i = p[i]; + } + if (!k) return i; + return ciclo[rt[i]][(pos[i] - pos[ciclo[rt[i]][0]] + k) % sz[rt[i]]]; + } + ll path(int i, ll k) { + auto query = [&](int l, int r) { + ll q = 0; + for (l += n, r += n; l <= r; ++l/=2, --r/=2) { + if (l%2 == 1) q = op(q, seg[l]); + if (r%2 == 0) q = op(q, seg[r]); + } + return q; + }; + ll ret = 0; + while (d[i] and k) { + int big = d[i] - d[pp[i]]; + if (big <= k) k -= big, ret = op(ret, jmp[i]), i = pp[i]; + else k--, ret = op(ret, val[i]), i = p[i]; + } + if (!k) return ret; + int first = pos[ciclo[rt[i]][0]], last = pos[ciclo[rt[i]].back()]; + + // k/sz[rt[i]] voltas completas + if (k/sz[rt[i]]) ret = op(ret, k/sz[rt[i]] * query(first, last)); + + k %= sz[rt[i]]; + if (!k) return ret; + int l = pos[i], r = first + (pos[i] - first + k - 1) % sz[rt[i]]; + if (l <= r) return op(ret, query(l, r)); + return op(ret, op(query(l, last), query(first, r))); + } +} +``` diff --git a/content/docs/Grafos/hopcroftKarp.md b/content/docs/Grafos/hopcroftKarp.md new file mode 100644 index 0000000..13c67aa --- /dev/null +++ b/content/docs/Grafos/hopcroftKarp.md @@ -0,0 +1,89 @@ +--- +weight: 10 +title: "Hopcroft Karp" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Computa matching maximo em grafo bipartido + + 'n' e 'm' sao quantos vertices tem em cada particao + + chamar add(i, j) para add aresta entre o cara i + + da particao A, e o cara j da particao B + + (entao i < n, j < m) + + + + O(|E| * sqrt(|V|)) com constante baixa + + Para grafos esparsos gerados aleatoriamente, roda em O(|E| * log(|V|)) + + com alta probabilidade + + + +Link original: [hopcroftKarp.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/hopcroftKarp.cpp) + +## Código +```cpp +mt19937 rng((int) chrono::steady_clock::now().time_since_epoch().count()); + +struct hopcroft_karp { + int n, m; + vector> g; + vector dist, nxt, ma, mb; + + hopcroft_karp(int n_, int m_) : n(n_), m(m_), g(n), + dist(n), nxt(n), ma(n, -1), mb(m, -1) {} + + void add(int a, int b) { g[a].push_back(b); } + + bool dfs(int i) { + for (int &id = nxt[i]; id < g[i].size(); id++) { + int j = g[i][id]; + if (mb[j] == -1 or (dist[mb[j]] == dist[i] + 1 and dfs(mb[j]))) { + ma[i] = j, mb[j] = i; + return true; + } + } + return false; + } + bool bfs() { + for (int i = 0; i < n; i++) dist[i] = n; + queue q; + for (int i = 0; i < n; i++) if (ma[i] == -1) { + dist[i] = 0; + q.push(i); + } + bool rep = 0; + while (q.size()) { + int i = q.front(); q.pop(); + for (int j : g[i]) { + if (mb[j] == -1) rep = 1; + else if (dist[mb[j]] > dist[i] + 1) { + dist[mb[j]] = dist[i] + 1; + q.push(mb[j]); + } + } + } + return rep; + } + int matching() { + int ret = 0; + for (auto& i : g) shuffle(i.begin(), i.end(), rng); + while (bfs()) { + for (int i = 0; i < n; i++) nxt[i] = 0; + for (int i = 0; i < n; i++) + if (ma[i] == -1 and dfs(i)) ret++; + } + return ret; + } +}; +``` diff --git a/content/docs/Grafos/johnson.md b/content/docs/Grafos/johnson.md new file mode 100644 index 0000000..8d26434 --- /dev/null +++ b/content/docs/Grafos/johnson.md @@ -0,0 +1,65 @@ +--- +weight: 10 +title: "Johnson" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + funciona igual ao Floyd-Warshall + + encontra o menor caminho entre todo + + par de vertices e retorna 1 sse tem + + ciclo negativo no grafo + + + + O(nm log(m)) + + + +Link original: [johnson.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/johnson.cpp) + +## Código +```cpp +vector> g[MAX]; // {vizinho, peso} +ll d[MAX][MAX]; + +bool johnson(int n) { + vector h(n, 0); + for (int i = 0; i <= n; i++) + for (int v = 0; v < n; v++) + for (auto [u, w] : g[v]) if (h[u] > h[v] + w) { + if (i == n) return 1; + h[u] = h[v] + w; + } + + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) d[i][j] = LINF; + d[i][i] = 0; + priority_queue> pq; + pq.emplace(0, i); + while (pq.size()) { + auto [ndist, v] = pq.top(); pq.pop(); + if (-ndist > d[i][v]) continue; + + for (auto [u, w] : g[v]) { + w += h[v] - h[u]; + if (d[i][u] > d[i][v] + w) { + d[i][u] = d[i][v] + w; + pq.emplace(-d[i][u], u); + } + } + } + for (int j = 0; j < n; j++) + d[i][j] += h[j] - h[i]; + } + + return 0; +} +``` diff --git a/content/docs/Grafos/kosaraju.md b/content/docs/Grafos/kosaraju.md new file mode 100644 index 0000000..24acb45 --- /dev/null +++ b/content/docs/Grafos/kosaraju.md @@ -0,0 +1,53 @@ +--- +weight: 10 +title: "Kosaraju" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + O(n + m) + + + +Link original: [kosaraju.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/kosaraju.cpp) + +## Código +```cpp +int n; +vector g[MAX]; +vector gi[MAX]; // grafo invertido +int vis[MAX]; +stack S; +int comp[MAX]; // componente conexo de cada vertice + +void dfs(int k) { + vis[k] = 1; + for (int i = 0; i < (int) g[k].size(); i++) + if (!vis[g[k][i]]) dfs(g[k][i]); + + S.push(k); +} + +void scc(int k, int c) { + vis[k] = 1; + comp[k] = c; + for (int i = 0; i < (int) gi[k].size(); i++) + if (!vis[gi[k][i]]) scc(gi[k][i], c); +} + +void kosaraju() { + for (int i = 0; i < n; i++) vis[i] = 0; + for (int i = 0; i < n; i++) if (!vis[i]) dfs(i); + + for (int i = 0; i < n; i++) vis[i] = 0; + while (S.size()) { + int u = S.top(); + S.pop(); + if (!vis[u]) scc(u, u); + } +} +``` diff --git a/content/docs/Grafos/kruskal.md b/content/docs/Grafos/kruskal.md new file mode 100644 index 0000000..075ac8d --- /dev/null +++ b/content/docs/Grafos/kruskal.md @@ -0,0 +1,48 @@ +--- +weight: 10 +title: "Kruskal" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Gera e retorna uma AGM e seu custo total a partir do vetor de arestas (edg) + + do grafo + + + + O(m log(m) + m a(m)) + + 864875 + + + +Link original: [kruskal.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/kruskal.cpp) + +## Código +```cpp +vector> edg; // {peso,[x,y]} + +// DSU em O(a(n)) +void dsu_build(); +int find(int a); +void unite(int a, int b); + +pair>> kruskal(int n) { + dsu_build(n); + sort(edg.begin(), edg.end()); + + ll cost = 0; + vector> mst; + for (auto [w,x,y] : edg) if (find(x) != find(y)) { + mst.emplace_back(w, x, y); + cost += w; + unite(x,y); + } + return {cost, mst}; +} +``` diff --git a/content/docs/Grafos/kuhn.md b/content/docs/Grafos/kuhn.md new file mode 100644 index 0000000..284dc74 --- /dev/null +++ b/content/docs/Grafos/kuhn.md @@ -0,0 +1,86 @@ +--- +weight: 10 +title: "Kuhn" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Computa matching maximo em grafo bipartido + + 'n' e 'm' sao quantos vertices tem em cada particao + + chamar add(i, j) para add aresta entre o cara i + + da particao A, e o cara j da particao B + + (entao i < n, j < m) + + Para recuperar o matching, basta olhar 'ma' e 'mb' + + 'recover' recupera o min vertex cover como um par de + + {caras da particao A, caras da particao B} + + + + O(|V| * |E|) + + Na pratica, parece rodar tao rapido quanto o Dinitz + + + +Link original: [kuhn.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/kuhn.cpp) + +## Código +```cpp +mt19937 rng((int) chrono::steady_clock::now().time_since_epoch().count()); + +struct kuhn { + int n, m; + vector> g; + vector vis, ma, mb; + + kuhn(int n_, int m_) : n(n_), m(m_), g(n), + vis(n+m), ma(n, -1), mb(m, -1) {} + + void add(int a, int b) { g[a].push_back(b); } + + bool dfs(int i) { + vis[i] = 1; + for (int j : g[i]) if (!vis[n+j]) { + vis[n+j] = 1; + if (mb[j] == -1 or dfs(mb[j])) { + ma[i] = j, mb[j] = i; + return true; + } + } + return false; + } + int matching() { + int ret = 0, aum = 1; + for (auto& i : g) shuffle(i.begin(), i.end(), rng); + while (aum) { + for (int j = 0; j < m; j++) vis[n+j] = 0; + aum = 0; + for (int i = 0; i < n; i++) + if (ma[i] == -1 and dfs(i)) ret++, aum = 1; + } + return ret; + } +}; + +pair, vector> recover(kuhn& K) { + K.matching(); + int n = K.n, m = K.m; + for (int i = 0; i < n+m; i++) K.vis[i] = 0; + for (int i = 0; i < n; i++) if (K.ma[i] == -1) K.dfs(i); + vector ca, cb; + for (int i = 0; i < n; i++) if (!K.vis[i]) ca.push_back(i); + for (int i = 0; i < m; i++) if (K.vis[n+i]) cb.push_back(i); + return {ca, cb}; +} +``` diff --git a/content/docs/Grafos/linetree.md b/content/docs/Grafos/linetree.md new file mode 100644 index 0000000..d58bd0d --- /dev/null +++ b/content/docs/Grafos/linetree.md @@ -0,0 +1,71 @@ +--- +weight: 10 +title: "Line Tree" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Reduz min-query em arvore para RMQ + + Se o grafo nao for uma arvore, as queries + + sao sobre a arvore geradora maxima + + Queries de minimo + + + + build - O(n log(n)) + + query - O(log(n)) + + + +Link original: [linetree.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/linetree.cpp) + +## Código +```cpp +int n; + +namespace linetree { + int id[MAX], seg[2*MAX], pos[MAX]; + vector v[MAX], val[MAX]; + vector > > ar; + + void add(int a, int b, int p) { ar.push_back({p, {a, b}}); } + void build() { + sort(ar.rbegin(), ar.rend()); + for (int i = 0; i < n; i++) id[i] = i, v[i] = {i}, val[i].clear(); + for (auto i : ar) { + int a = id[i.second.first], b = id[i.second.second]; + if (a == b) continue; + if (v[a].size() < v[b].size()) swap(a, b); + for (auto j : v[b]) id[j] = a, v[a].push_back(j); + val[a].push_back(i.first); + for (auto j : val[b]) val[a].push_back(j); + v[b].clear(), val[b].clear(); + } + vector vv; + for (int i = 0; i < n; i++) for (int j = 0; j < v[i].size(); j++) { + pos[v[i][j]] = vv.size(); + if (j + 1 < v[i].size()) vv.push_back(val[i][j]); + else vv.push_back(0); + } + for (int i = n; i < 2*n; i++) seg[i] = vv[i-n]; + for (int i = n-1; i; i--) seg[i] = min(seg[2*i], seg[2*i+1]); + } + int query(int a, int b) { + if (id[a] != id[b]) return 0; // nao estao conectados + a = pos[a], b = pos[b]; + if (a > b) swap(a, b); + b--; + int ans = INF; + for (a += n, b += n; a <= b; ++a/=2, --b/=2) ans = min({ans, seg[a], seg[b]}); + return ans; + } +}; +``` diff --git a/content/docs/Grafos/lowerBoundMaxFlow.md b/content/docs/Grafos/lowerBoundMaxFlow.md new file mode 100644 index 0000000..d44ce6e --- /dev/null +++ b/content/docs/Grafos/lowerBoundMaxFlow.md @@ -0,0 +1,66 @@ +--- +weight: 10 +title: "Max flow com lower bound" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + add(a, b, l, r): + + adiciona aresta de a pra b, onde precisa passar f de fluxo, l <= f <= r + + add(a, b, c): + + adiciona aresta de a pra b com capacidade c + + + + Mesma complexidade do Dinitz + + + +Link original: [lowerBoundMaxFlow.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/lowerBoundMaxFlow.cpp) + +## Código +```cpp +struct lb_max_flow : dinitz { + vector d; + lb_max_flow(int n) : dinitz(n + 2), d(n, 0) {} + void add(int a, int b, int l, int r) { + d[a] -= l; + d[b] += l; + dinitz::add(a, b, r - l); + } + void add(int a, int b, int c) { + dinitz::add(a, b, c); + } + bool has_circulation() { + int n = d.size(); + + ll cost = 0; + for (int i = 0; i < n; i++) { + if (d[i] > 0) { + cost += d[i]; + dinitz::add(n, i, d[i]); + } else if (d[i] < 0) { + dinitz::add(i, n+1, -d[i]); + } + } + + return (dinitz::max_flow(n, n+1) == cost); + } + bool has_flow(int src, int snk) { + dinitz::add(snk, src, INF); + return has_circulation(); + } + ll max_flow(int src, int snk) { + if (!has_flow(src, snk)) return -1; + dinitz::F = 0; + return dinitz::max_flow(src, snk); + } +}; +``` diff --git a/content/docs/Grafos/minCostMaxFlow.md b/content/docs/Grafos/minCostMaxFlow.md new file mode 100644 index 0000000..b3b3309 --- /dev/null +++ b/content/docs/Grafos/minCostMaxFlow.md @@ -0,0 +1,149 @@ +--- +weight: 10 +title: "MinCostMaxFlow" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + min_cost_flow(s, t, f) computa o par (fluxo, custo) + + com max(fluxo) <= f que tenha min(custo) + + min_cost_flow(s, t) -> Fluxo maximo de custo minimo de s pra t + + Se for um dag, da pra substituir o SPFA por uma DP pra nao + + pagar O(nm) no comeco + + Se nao tiver aresta com custo negativo, nao precisa do SPFA + + + + O(nm + f * m log n) + + + +Link original: [minCostMaxFlow.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/minCostMaxFlow.cpp) + +## Código +```cpp +template struct mcmf { + struct edge { + int to, rev, flow, cap; // para, id da reversa, fluxo, capacidade + bool res; // se eh reversa + T cost; // custo da unidade de fluxo + edge() : to(0), rev(0), flow(0), cap(0), cost(0), res(false) {} + edge(int to_, int rev_, int flow_, int cap_, T cost_, bool res_) + : to(to_), rev(rev_), flow(flow_), cap(cap_), res(res_), cost(cost_) {} + }; + + vector> g; + vector par_idx, par; + T inf; + vector dist; + + mcmf(int n) : g(n), par_idx(n), par(n), inf(numeric_limits::max()/3) {} + + void add(int u, int v, int w, T cost) { // de u pra v com cap w e custo cost + edge a = edge(v, g[v].size(), 0, w, cost, false); + edge b = edge(u, g[u].size(), 0, 0, -cost, true); + + g[u].push_back(a); + g[v].push_back(b); + } + + vector spfa(int s) { // nao precisa se nao tiver custo negativo + deque q; + vector is_inside(g.size(), 0); + dist = vector(g.size(), inf); + + dist[s] = 0; + q.push_back(s); + is_inside[s] = true; + + while (!q.empty()) { + int v = q.front(); + q.pop_front(); + is_inside[v] = false; + + for (int i = 0; i < g[v].size(); i++) { + auto [to, rev, flow, cap, res, cost] = g[v][i]; + if (flow < cap and dist[v] + cost < dist[to]) { + dist[to] = dist[v] + cost; + + if (is_inside[to]) continue; + if (!q.empty() and dist[to] > dist[q.front()]) q.push_back(to); + else q.push_front(to); + is_inside[to] = true; + } + } + } + return dist; + } + bool dijkstra(int s, int t, vector& pot) { + priority_queue, vector>, greater<>> q; + dist = vector(g.size(), inf); + dist[s] = 0; + q.emplace(0, s); + while (q.size()) { + auto [d, v] = q.top(); + q.pop(); + if (dist[v] < d) continue; + for (int i = 0; i < g[v].size(); i++) { + auto [to, rev, flow, cap, res, cost] = g[v][i]; + cost += pot[v] - pot[to]; + if (flow < cap and dist[v] + cost < dist[to]) { + dist[to] = dist[v] + cost; + q.emplace(dist[to], to); + par_idx[to] = i, par[to] = v; + } + } + } + return dist[t] < inf; + } + + pair min_cost_flow(int s, int t, int flow = INF) { + vector pot(g.size(), 0); + pot = spfa(s); // mudar algoritmo de caminho minimo aqui + + int f = 0; + T ret = 0; + while (f < flow and dijkstra(s, t, pot)) { + for (int i = 0; i < g.size(); i++) + if (dist[i] < inf) pot[i] += dist[i]; + + int mn_flow = flow - f, u = t; + while (u != s){ + mn_flow = min(mn_flow, + g[par[u]][par_idx[u]].cap - g[par[u]][par_idx[u]].flow); + u = par[u]; + } + + ret += pot[t] * mn_flow; + + u = t; + while (u != s) { + g[par[u]][par_idx[u]].flow += mn_flow; + g[u][g[par[u]][par_idx[u]].rev].flow -= mn_flow; + u = par[u]; + } + + f += mn_flow; + } + + return make_pair(f, ret); + } + + // Opcional: retorna as arestas originais por onde passa flow = cap + vector> recover() { + vector> used; + for (int i = 0; i < g.size(); i++) for (edge e : g[i]) + if(e.flow == e.cap && !e.res) used.push_back({i, e.to}); + return used; + } +}; +``` diff --git a/content/docs/Grafos/prufer.md b/content/docs/Grafos/prufer.md new file mode 100644 index 0000000..d3cccdd --- /dev/null +++ b/content/docs/Grafos/prufer.md @@ -0,0 +1,73 @@ +--- +weight: 10 +title: "Prufer code" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Traduz de lista de arestas para prufer code + + e vice-versa + + Os vertices tem label de 0 a n-1 + + Todo array com n-2 posicoes e valores de + + 0 a n-1 sao prufer codes validos + + + + O(n) + + + +Link original: [prufer.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/prufer.cpp) + +## Código +```cpp +vector to_prufer(vector> tree) { + int n = tree.size()+1; + vector d(n, 0); + vector> g(n); + for (auto [a, b] : tree) d[a]++, d[b]++, + g[a].push_back(b), g[b].push_back(a); + vector pai(n, -1); + queue q; q.push(n-1); + while (q.size()) { + int u = q.front(); q.pop(); + for (int v : g[u]) if (v != pai[u]) + pai[v] = u, q.push(v); + } + int idx, x; + idx = x = find(d.begin(), d.end(), 1) - d.begin(); + vector ret; + for (int i = 0; i < n-2; i++) { + int y = pai[x]; + ret.push_back(y); + if (--d[y] == 1 and y < idx) x = y; + else idx = x = find(d.begin()+idx+1, d.end(), 1) - d.begin(); + } + return ret; +} + +vector> from_prufer(vector p) { + int n = p.size()+2; + vector d(n, 1); + for (int i : p) d[i]++; + p.push_back(n-1); + int idx, x; + idx = x = find(d.begin(), d.end(), 1) - d.begin(); + vector> ret; + for (int y : p) { + ret.push_back({x, y}); + if (--d[y] == 1 and y < idx) x = y; + else idx = x = find(d.begin()+idx+1, d.end(), 1) - d.begin(); + } + return ret; +} + +``` diff --git a/content/docs/Grafos/sack.md b/content/docs/Grafos/sack.md new file mode 100644 index 0000000..1d1f7d7 --- /dev/null +++ b/content/docs/Grafos/sack.md @@ -0,0 +1,53 @@ +--- +weight: 10 +title: "Sack (DSU em arvores)" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Responde queries de todas as sub-arvores + + offline + + + + O(n log(n)) + + + +Link original: [sack.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/sack.cpp) + +## Código +```cpp +int sz[MAX], cor[MAX], cnt[MAX]; +vector g[MAX]; + +void build(int k, int d=0) { + sz[k] = 1; + for (auto& i : g[k]) { + build(i, d+1); sz[k] += sz[i]; + if (sz[i] > sz[g[k][0]]) swap(i, g[k][0]); + } +} + +void compute(int k, int x, bool dont=1) { + cnt[cor[k]] += x; + for (int i = dont; i < g[k].size(); i++) + compute(g[k][i], x, 0); +} + +void solve(int k, bool keep=0) { + for (int i = int(g[k].size())-1; i >= 0; i--) + solve(g[k][i], !i); + compute(k, 1); + + // agora cnt[i] tem quantas vezes a cor + // i aparece na sub-arvore do k + + if (!keep) compute(k, -1, 0); +} +``` diff --git a/content/docs/Grafos/stableMarriage.md b/content/docs/Grafos/stableMarriage.md new file mode 100644 index 0000000..09aaf77 --- /dev/null +++ b/content/docs/Grafos/stableMarriage.md @@ -0,0 +1,68 @@ +--- +weight: 10 +title: "Stable Marriage" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Emparelha todos os elementos de A com elementos de B + + de forma que nao exista um par x \in A, y \in B + + e x nao pareado com y tal que x prefira parear com y + + e y prefira parear com x. + + + + a[i] contem os elementos de B ordenados por preferencia de i + + b[j] contem os elementos de A ordenados por preferencia de j + + |A| <= |B| + + + + Retorna um vetor v de tamanho |A| onde v[i] guarda o match de i. + + + + O(|A| * |B|) + + + +Link original: [stableMarriage.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/stableMarriage.cpp) + +## Código +```cpp +vector stable_marriage(vector> &a, vector> &b) { + int n = a.size(), m = b.size(); + assert(a[0].size() == m and b[0].size() == n and n <= m); + vector match(m, -1), it(n, 0); + vector inv_b(m, vector(n)); + for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) + inv_b[i][b[i][j]] = j; + + queue q; + for (int i = 0; i < n; i++) q.push(i); + while (q.size()) { + int i = q.front(); q.pop(); + int j = a[i][it[i]]; + + if (match[j] == -1) match[j] = i; + else if (inv_b[j][i] < inv_b[j][match[j]]) { + q.emplace(match[j]); + it[match[j]]++; + match[j] = i; + } else q.emplace(i), it[i]++; + } + + vector ret(n); + for (int i = 0; i < m; i++) if (match[i] != -1) ret[match[i]] = i; + return ret; +} +``` diff --git a/content/docs/Grafos/tarjan.md b/content/docs/Grafos/tarjan.md new file mode 100644 index 0000000..384870a --- /dev/null +++ b/content/docs/Grafos/tarjan.md @@ -0,0 +1,53 @@ +--- +weight: 10 +title: "Tarjan para SCC" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + O(n + m) + + + +Link original: [tarjan.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/tarjan.cpp) + +## Código +```cpp +vector g[MAX]; +stack s; +int vis[MAX], comp[MAX]; +int id[MAX]; + +// se quiser comprimir ciclo ou achar ponte em grafo nao direcionado, +// colocar um if na dfs para nao voltar pro pai da DFS tree +int dfs(int i, int& t) { + int lo = id[i] = t++; + s.push(i); + vis[i] = 2; + + for (int j : g[i]) { + if (!vis[j]) lo = min(lo, dfs(j, t)); + else if (vis[j] == 2) lo = min(lo, id[j]); + } + + // aresta de i pro pai eh uma ponte (no caso nao direcionado) + if (lo == id[i]) while (1) { + int u = s.top(); s.pop(); + vis[u] = 1, comp[u] = i; + if (u == i) break; + } + + return lo; +} + +void tarjan(int n) { + int t = 0; + for (int i = 0; i < n; i++) vis[i] = 0; + + for (int i = 0; i < n; i++) if (!vis[i]) dfs(i, t); +} +``` diff --git a/content/docs/Grafos/topoSort.md b/content/docs/Grafos/topoSort.md new file mode 100644 index 0000000..6be11bf --- /dev/null +++ b/content/docs/Grafos/topoSort.md @@ -0,0 +1,46 @@ +--- +weight: 10 +title: "Topological Sort" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Retorna uma ordenacaoo topologica de g + + Se g nao for DAG retorna um vetor vazio + + + + O(n + m) + + + +Link original: [topoSort.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/topoSort.cpp) + +## Código +```cpp +vector g[MAX]; + +vector topo_sort(int n) { + vector ret(n,-1), vis(n,0); + + int pos = n-1, dag = 1; + function dfs = [&](int v) { + vis[v] = 1; + for (auto u : g[v]) { + if (vis[u] == 1) dag = 0; + else if (!vis[u]) dfs(u); + } + ret[pos--] = v, vis[v] = 2; + }; + + for (int i = 0; i < n; i++) if (!vis[i]) dfs(i); + + if (!dag) ret.clear(); + return ret; +} +``` diff --git a/content/docs/Grafos/treeIsomorf.md b/content/docs/Grafos/treeIsomorf.md new file mode 100644 index 0000000..d3a43d0 --- /dev/null +++ b/content/docs/Grafos/treeIsomorf.md @@ -0,0 +1,129 @@ +--- +weight: 10 +title: "Isomorfismo de arvores" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + thash() retorna o hash da arvore (usando centroids como vertices especiais). + + Duas arvores sao isomorfas sse seu hash eh o mesmo + + + + O(|V|.log(|V|)) + + + +Link original: [treeIsomorf.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/treeIsomorf.cpp) + +## Código +```cpp +map, int> mphash; + +struct tree { + int n; + vector> g; + vector sz, cs; + + tree(int n_) : n(n_), g(n_), sz(n_) {} + + void dfs_centroid(int v, int p) { + sz[v] = 1; + bool cent = true; + for (int u : g[v]) if (u != p) { + dfs_centroid(u, v), sz[v] += sz[u]; + if(sz[u] > n/2) cent = false; + } + if (cent and n - sz[v] <= n/2) cs.push_back(v); + } + int fhash(int v, int p) { + vector h; + for (int u : g[v]) if (u != p) h.push_back(fhash(u, v)); + sort(h.begin(), h.end()); + if (!mphash.count(h)) mphash[h] = mphash.size(); + return mphash[h]; + } + ll thash() { + cs.clear(); + dfs_centroid(0, -1); + if (cs.size() == 1) return fhash(cs[0], -1); + ll h1 = fhash(cs[0], cs[1]), h2 = fhash(cs[1], cs[0]); + return (min(h1, h2) << 30) + max(h1, h2); + } +}; + + +// Versao mais rapida com hash, ideal para hash de floresta. +// subtree_hash(v, p) retorna o hash da subarvore enraizada em v com pai p. +// tree_hash() retorna o hash da arvore. +// forest_hash() retorna o hash da floresta. +// use o vetor forb[] para marcar vertices que nao podem ser visitados. +// +// O(|V|.log(|V|)) + +mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); + +int uniform(ll l, ll r) { + uniform_int_distribution uid(l, r); + return uid(rng); +} + +const int MOD = 1e9 + 7; +const int H = 13; +const int P = uniform(1, MOD-1); +const int P2 = uniform(1, MOD-1); + +struct tree { + int fn; + vector> g; + vector sz, cs; + vector forb; + + tree(int n_) : fn(n_), g(n_), sz(n_), forb(n_) {} + + void dfs_size(int v, int p) { + sz[v] = 1; + for (int u : g[v]) if (u != p and !forb[u]) { + dfs_size(u, v), sz[v] += sz[u]; + } + } + void dfs_centroid(int v, int p, int n) { + bool cent = true; + for (int u : g[v]) if (u != p and !forb[u]) { + dfs_centroid(u, v, n); + if(sz[u] > n/2) cent = false; + } + if (cent and n - sz[v] <= n/2) cs.push_back(v); + } + int subtree_hash(int v, int p) { + int h = H; + for (int u : g[v]) if (u != p and !forb[u]) { + h = ll(h) * (P + subtree_hash(u, v)) % MOD; + } + return h; + } + int tree_hash(int v=0) { + cs.clear(); + dfs_size(v, -1); + dfs_centroid(v, -1, sz[v]); + if (cs.size() == 1) return subtree_hash(cs[0], -1); + assert (cs.size() == 2); + int h1 = subtree_hash(cs[0], cs[1]); + int h2 = subtree_hash(cs[1], cs[0]); + return ll(P + h1) * (P + h2) % MOD; + } + int forest_hash() { + fill(sz.begin(), sz.end(), 0); + int hash = 1; + for (int v = 0; v < fn; v++) if (!sz[v] and !forb[v]) { + hash = hash * ll(P2 + tree_hash(v)) % MOD; + } + return hash; + } +}; +``` diff --git a/content/docs/Grafos/virtualTree.md b/content/docs/Grafos/virtualTree.md new file mode 100644 index 0000000..4c2f998 --- /dev/null +++ b/content/docs/Grafos/virtualTree.md @@ -0,0 +1,59 @@ +--- +weight: 10 +title: "Virtual Tree" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Comprime uma arvore dado um conjunto S de vertices, de forma que + + o conjunto de vertices da arvore comprimida contenha S e seja + + minimal e fechado sobre a operacao de LCA + + Se |S| = k, a arvore comprimida tem menos que 2k vertices + + As arestas de virt possuem a distancia do vertice ate o vizinho + + Retorna a raiz da virtual tree + + + + lca::pos deve ser a ordem de visitacao no dfs + + voce pode usar o LCAcomHLD, por exemplo + + + + O(k log(k)) + + + +Link original: [virtualTree.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/virtualTree.cpp) + +## Código +```cpp +vector> virt[MAX]; + +#warning lembrar de buildar o LCA antes +int build_virt(vector v) { + auto cmp = [&](int i, int j) { return lca::pos[i] < lca::pos[j]; }; + sort(v.begin(), v.end(), cmp); + for (int i = v.size()-1; i; i--) v.push_back(lca::lca(v[i], v[i-1])); + sort(v.begin(), v.end(), cmp); + v.erase(unique(v.begin(), v.end()), v.end()); + for (int i = 0; i < v.size(); i++) virt[v[i]].clear(); + for (int i = 1; i < v.size(); i++) virt[lca::lca(v[i-1], v[i])].clear(); + for (int i = 1; i < v.size(); i++) { + int parent = lca::lca(v[i-1], v[i]); + int d = lca::dist(parent, v[i]); +#warning soh to colocando aresta descendo + virt[parent].emplace_back(v[i], d); + } + return v[0]; +} +``` diff --git a/content/docs/Matematica/2sat.md b/content/docs/Matematica/2sat.md new file mode 100644 index 0000000..585d5e6 --- /dev/null +++ b/content/docs/Matematica/2sat.md @@ -0,0 +1,91 @@ +--- +weight: 10 +title: "2-SAT" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + solve() retorna um par, o first fala se eh possivel + + atribuir, o second fala se cada variavel eh verdadeira + + + + O(|V|+|E|) = O(#variaveis + #restricoes) + + + +Link original: [2sat.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Matematica/2sat.cpp) + +## Código +```cpp +struct sat { + int n, tot; + vector> g; + vector vis, comp, id, ans; + stack s; + + sat() {} + sat(int n_) : n(n_), tot(n), g(2*n) {} + + int dfs(int i, int& t) { + int lo = id[i] = t++; + s.push(i), vis[i] = 2; + for (int j : g[i]) { + if (!vis[j]) lo = min(lo, dfs(j, t)); + else if (vis[j] == 2) lo = min(lo, id[j]); + } + if (lo == id[i]) while (1) { + int u = s.top(); s.pop(); + vis[u] = 1, comp[u] = i; + if ((u>>1) < n and ans[u>>1] == -1) ans[u>>1] = ~u&1; + if (u == i) break; + } + return lo; + } + + void add_impl(int x, int y) { // x -> y = !x ou y + x = x >= 0 ? 2*x : -2*x-1; + y = y >= 0 ? 2*y : -2*y-1; + g[x].push_back(y); + g[y^1].push_back(x^1); + } + void add_cl(int x, int y) { // x ou y + add_impl(~x, y); + } + void add_xor(int x, int y) { // x xor y + add_cl(x, y), add_cl(~x, ~y); + } + void add_eq(int x, int y) { // x = y + add_xor(~x, y); + } + void add_true(int x) { // x = T + add_impl(~x, x); + } + void at_most_one(vector v) { // no max um verdadeiro + g.resize(2*(tot+v.size())); + for (int i = 0; i < v.size(); i++) { + add_impl(tot+i, ~v[i]); + if (i) { + add_impl(tot+i, tot+i-1); + add_impl(v[i], tot+i-1); + } + } + tot += v.size(); + } + + pair> solve() { + ans = vector(n, -1); + int t = 0; + vis = comp = id = vector(2*tot, 0); + for (int i = 0; i < 2*tot; i++) if (!vis[i]) dfs(i, t); + for (int i = 0; i < tot; i++) + if (comp[2*i] == comp[2*i+1]) return {false, {}}; + return {true, ans}; + } +}; +``` diff --git a/content/docs/Matematica/_index.md b/content/docs/Matematica/_index.md new file mode 100644 index 0000000..eba21c7 --- /dev/null +++ b/content/docs/Matematica/_index.md @@ -0,0 +1,8 @@ +--- +weight: 10 +title: "Matematica" +draft: false +date: "2024-05-09T17:19:25-0300" +description: "" +publishdate: "2024-05-09T17:19:25-0300" +--- diff --git a/content/docs/Matematica/berlekampMassey.md b/content/docs/Matematica/berlekampMassey.md new file mode 100644 index 0000000..65409a0 --- /dev/null +++ b/content/docs/Matematica/berlekampMassey.md @@ -0,0 +1,110 @@ +--- +weight: 10 +title: "Berlekamp-Massey" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + guess_kth(s, k) chuta o k-esimo (0-based) termo + + de uma recorrencia linear que gera s + + Para uma rec. lin. de ordem x, se passar 2x termos + + vai gerar a certa + + Usar aritmetica modular + + + + Pro fast_evaluate, precisa de ntt e divmod (powerSeries.cpp) + + + + Complexidades: (n = |s|) + + evaluate: O(n^2 log k) + + fast_evaluate: O(n log n log k) + + berlekampMassey: O(n^2 + O(evaluate)) + + + +Link original: [berlekampMassey.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Matematica/berlekampMassey.cpp) + +## Código +```cpp +template T evaluate(vector c, vector s, ll k) { + int n = c.size(); + assert(c.size() <= s.size()); + + auto mul = [&](const vector &a, const vector &b) { + vector ret(a.size() + b.size() - 1); + for (int i = 0; i < a.size(); i++) for (int j = 0; j < b.size(); j++) + ret[i+j] += a[i] * b[j]; + for (int i = ret.size()-1; i >= n; i--) for (int j = n-1; j >= 0; j--) + ret[i-j-1] += ret[i] * c[j]; + ret.resize(min(ret.size(), n)); + return ret; + }; + + vector a = n == 1 ? vector({c[0]}) : vector({0, 1}), x = {1}; + while (k) { + if (k&1) x = mul(x, a); + a = mul(a, a), k >>= 1; + } + x.resize(n); + + T ret = 0; + for (int i = 0; i < n; i++) ret += x[i] * s[i]; + return ret; +} + +mint fast_evaluate(poly c, poly s, ll k) { + if (k < s.size()) return s[k]; + int n = c.size(); + assert(c.size() <= s.size()); + + auto f = poly(n + 1, 1); + for (int i = 0; i < n; i++) f[i] = -c[n-i-1]; + + poly a = n == 1 ? poly({c[0]}) : poly({0, 1}), x = {1}; + while (k) { + if (k&1) x = divmod(convolution(x, a), f).second; + a = divmod(convolution(a, a), f).second, k >>= 1; + } + + mint ret = 0; + for (int i = 0; i < n; i++) ret += x[i] * s[i]; + return ret; +} + +template vector berlekamp_massey(vector s) { + int n = s.size(), l = 0, m = 1; + vector b(n), c(n); + T ld = b[0] = c[0] = 1; + for (int i = 0; i < n; i++, m++) { + T d = s[i]; + for (int j = 1; j <= l; j++) d += c[j] * s[i-j]; + if (d == 0) continue; + vector temp = c; + T coef = d / ld; + for (int j = m; j < n; j++) c[j] -= coef * b[j-m]; + if (2 * l <= i) l = i + 1 - l, b = temp, ld = d, m = 0; + } + c.resize(l + 1); + c.erase(c.begin()); + for (T& x : c) x = -x; + return c; +} + +template T guess_kth(const vector& s, ll k) { + auto c = berlekamp_massey(s); + return evaluate(c, s, k); +} +``` diff --git a/content/docs/Matematica/chinese.md b/content/docs/Matematica/chinese.md new file mode 100644 index 0000000..fa9985b --- /dev/null +++ b/content/docs/Matematica/chinese.md @@ -0,0 +1,46 @@ +--- +weight: 10 +title: "Teorema Chines do Resto" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Combina equacoes modulares lineares: x = a (mod m) + + O m final eh o lcm dos m's, e a resposta eh unica mod o lcm + + Os m nao precisam ser coprimos + + Se nao tiver solucao, o 'a' vai ser -1 + + + +Link original: [chinese.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Matematica/chinese.cpp) + +## Código +```cpp +template tuple ext_gcd(T a, T b) { + if (!a) return {b, 0, 1}; + auto [g, x, y] = ext_gcd(b%a, a); + return {g, y - b/a*x, x}; +} + +template struct crt { + T a, m; + + crt() : a(0), m(1) {} + crt(T a_, T m_) : a(a_), m(m_) {} + crt operator * (crt C) { + auto [g, x, y] = ext_gcd(m, C.m); + if ((a - C.a) % g) a = -1; + if (a == -1 or C.a == -1) return crt(-1, 0); + T lcm = m/g*C.m; + T ans = a + (x*(C.a-a)/g % (C.m/g))*m; + return crt((ans % lcm + lcm) % lcm, lcm); + } +}; +``` diff --git a/content/docs/Matematica/convolution.md b/content/docs/Matematica/convolution.md new file mode 100644 index 0000000..dbb3c2f --- /dev/null +++ b/content/docs/Matematica/convolution.md @@ -0,0 +1,135 @@ +--- +weight: 10 +title: "FFT" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Chamar convolution com vector> para FFT + + Precisa do mint para NTT + + + + O(n log(n)) + + + + Para FFT + +Link original: [convolution.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Matematica/convolution.cpp) + +## Código +```cpp +void get_roots(bool f, int n, vector>& roots) { + const static double PI = acosl(-1); + for (int i = 0; i < n/2; i++) { + double alpha = i*((2*PI)/n); + if (f) alpha = -alpha; + roots[i] = {cos(alpha), sin(alpha)}; + } +} + +// Para NTT +template +void get_roots(bool f, int n, vector>& roots) { + mod_int

r; + int ord; + if (p == 998244353) { + r = 102292; + ord = (1 << 23); + } else if (p == 754974721) { + r = 739831874; + ord = (1 << 24); + } else if (p == 167772161) { + r = 243; + ord = (1 << 25); + } else assert(false); + + if (f) r = r^(p - 1 -ord/n); + else r = r^(ord/n); + roots[0] = 1; + for (int i = 1; i < n/2; i++) roots[i] = roots[i-1]*r; +} + +template void fft(vector& a, bool f, int N, vector& rev) { + for (int i = 0; i < N; i++) if (i < rev[i]) swap(a[i], a[rev[i]]); + int l, r, m; + vector roots(N); + for (int n = 2; n <= N; n *= 2) { + get_roots(f, n, roots); + for (int pos = 0; pos < N; pos += n) { + l = pos + 0, r = pos + n/2, m = 0; + while (m < n/2) { + auto t = roots[m] * a[r]; + a[r] = a[l] - t; + a[l] = a[l] + t; + l++, r++, m++; + } + } + } + if (f) { + auto invN = T(1) / T(N); + for (int i = 0; i < N; i++) a[i] = a[i] * invN; + } +} + +template vector convolution(vector& a, vector& b) { + vector l(a.begin(), a.end()), r(b.begin(), b.end()); + int N = l.size()+r.size()-1; + int n = 1, log_n = 0; + while (n <= N) n *= 2, log_n++; + vector rev(n); + for (int i = 0; i < n; i++) { + rev[i] = 0; + for (int j = 0; j < log_n; j++) if (i>>j&1) + rev[i] |= 1 << (log_n-1-j); + } + assert(N <= n); + l.resize(n); + r.resize(n); + fft(l, false, n, rev); + fft(r, false, n, rev); + for (int i = 0; i < n; i++) l[i] *= r[i]; + fft(l, true, n, rev); + l.resize(N); + return l; +} + +// NTT +template vector> ntt(vector& a, vector& b) { + vector> A(a.begin(), a.end()), B(b.begin(), b.end()); + return convolution(A, B); +} + +// Convolucao de inteiro +// +// Precisa do CRT +// +// Tabela de valores: +// [0,1] - +// [-1e5, 1e5] - +// [-1e9, 1e9] - <__int128, 3> +template +vector int_convolution(vector& a, vector& b) { + static const int M1 = 998244353, M2 = 754974721, M3 = 167772161; + + auto c1 = ntt(a, b); + auto c2 = (mods >= 2 ? ntt(a, b) : vector>()); + auto c3 = (mods >= 3 ? ntt(a, b) : vector>()); + + vector ans; + for (int i = 0; i < c1.size(); i++) { + crt at(c1[i].v, M1); + if (mods >= 2) at = at * crt(c2[i].v, M2); + if (mods >= 3) at = at * crt(c3[i].v, M3); + ans.push_back(at.a); + if (at.a > at.m/2) ans.back() -= at.m; + } + return ans; +} +``` diff --git a/content/docs/Matematica/coprimeBasis.md b/content/docs/Matematica/coprimeBasis.md new file mode 100644 index 0000000..550aa26 --- /dev/null +++ b/content/docs/Matematica/coprimeBasis.md @@ -0,0 +1,77 @@ +--- +weight: 10 +title: "Coprime Basis" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Dado um conjunto de elementos A constroi uma base B + + de fatores coprimos tal que todo elemento A[i] + + pode ser fatorado como A[i] = \prod B[j]^p_ij + + + + Sendo n o numero de inserts, a complexidade esperada fica + + O(n*(n*loglog(MAX) + log(MAX)^2)) + + + + No pior caso, podemos trocar n*loglog(MAX) por + + 8n, se MAX <= 1e6 + + 10n, se MAX <= 1e9 + + 16n, se MAX <= 1e18 + + 26n, se MAX <= 1e36 + + + +Link original: [coprimeBasis.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Matematica/coprimeBasis.cpp) + +## Código +```cpp +template struct coprime_basis { + vector basis; + + coprime_basis() {} + coprime_basis(vector v) { for (T i : v) insert(i); } + + void insert(T z) { + int n = basis.size(); + basis.push_back(z); + for (int i = n; i < basis.size(); i++) { + for (int j = (i != n) ? i+1 : 0; j < basis.size(); j++) { + if (i == j) continue; + T &x = basis[i]; + if (x == 1) { + j = INF; + continue; + } + T &y = basis[j]; + T g = gcd(x, y); + if (g == 1) continue; + y /= g, x /= g; + basis.push_back(g); + } + } + basis.erase(remove(basis.begin(), basis.end(), 1), basis.end()); + } + + vector factor(T x) { + vector fat(basis.size()); + for (int i = 0; i < basis.size(); i++) { + while (x % basis[i] == 0) x /= basis[i], fat[i]++; + } + return fat; + } +}; +``` diff --git a/content/docs/Matematica/crivo.md b/content/docs/Matematica/crivo.md new file mode 100644 index 0000000..a627d20 --- /dev/null +++ b/content/docs/Matematica/crivo.md @@ -0,0 +1,171 @@ +--- +weight: 10 +title: "Crivo de Eratosthenes" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + "O" crivo + + + + Encontra maior divisor primo + + Um numero eh primo sse divi[x] == x + + fact fatora um numero <= lim + + A fatoracao sai ordenada + + + + crivo - O(n log(log(n))) + + fact - O(log(n)) + + + +Link original: [crivo.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Matematica/crivo.cpp) + +## Código +```cpp +int divi[MAX]; + +void crivo(int lim) { + for (int i = 1; i <= lim; i++) divi[i] = 1; + + for (int i = 2; i <= lim; i++) if (divi[i] == 1) + for (int j = i; j <= lim; j += i) divi[j] = i; +} + +#warning A funcao fact ira adicionar o 1 no vetor se voce tentar fatorar especificamente o numero 1 +void fact(vector& v, int n) { + if (n != divi[n]) fact(v, n/divi[n]); + v.push_back(divi[n]); +} + +// Crivo linear +// +// Mesma coisa que o de cima, mas tambem +// calcula a lista de primos +// +// O(n) + +int divi[MAX]; +vector primes; + +void crivo(int lim) { + divi[1] = 1; + for (int i = 2; i <= lim; i++) { + if (divi[i] == 0) divi[i] = i, primes.push_back(i); + for (int j : primes) { + if (j > divi[i] or i*j > lim) break; + divi[i*j] = j; + } + } +} + +// Crivo de divisores +// +// Encontra numero de divisores +// ou soma dos divisores +// +// O(n log(n)) + +int divi[MAX]; + +void crivo(int lim) { + for (int i = 1; i <= lim; i++) divi[i] = 1; + + for (int i = 2; i <= lim; i++) + for (int j = i; j <= lim; j += i) { + // para numero de divisores + divi[j]++; + // para soma dos divisores + divi[j] += i; + } +} + +// Crivo de totiente +// +// Encontra o valor da funcao +// totiente de Euler +// +// O(n log(log(n))) + +int tot[MAX]; + +void crivo(int lim) { + for (int i = 1; i <= lim; i++) { + tot[i] += i; + for (int j = 2*i; j <= lim; j += i) + tot[j] -= tot[i]; + } +} + +// Crivo de funcao de mobius +// +// O(n log(log(n))) + +char meb[MAX]; + +void crivo(int lim) { + for (int i = 2; i <= lim; i++) meb[i] = 2; + meb[1] = 1; + for (int i = 2; i <= lim; i++) if (meb[i] == 2) + for (int j = i; j <= lim; j += i) if (meb[j]) { + if (meb[j] == 2) meb[j] = 1; + meb[j] *= j/i%i ? -1 : 0; + } +} + +// Crivo linear de funcao multiplicativa +// +// Computa f(i) para todo 1 <= i <= n, sendo f +// uma funcao multiplicativa (se gcd(a,b) = 1, +// entao f(a*b) = f(a)*f(b)) +// f_prime tem que computar f de um primo, e +// add_prime tem que computar f(p^(k+1)) dado f(p^k) e p +// Se quiser computar f(p^k) dado p e k, usar os comentarios +// +// O(n) + +vector primes; +int f[MAX], pot[MAX]; +//int expo[MAX]; + +void sieve(int lim) { + // Funcoes para soma dos divisores: + auto f_prime = [](int p) { return p+1; }; + auto add_prime = [](int fpak, int p) { return fpak*p+1; }; + //auto f_pak = [](int p, int k) {}; + + f[1] = 1; + for (int i = 2; i <= lim; i++) { + if (!pot[i]) { + primes.push_back(i); + f[i] = f_prime(i), pot[i] = i; + //expo[i] = 1; + } + for (int p : primes) { + if (i*p > lim) break; + if (i%p == 0) { + f[i*p] = f[i / pot[i]] * add_prime(f[pot[i]], p); + // se for descomentar, tirar a linha de cima tambem + //f[i*p] = f[i / pot[i]] * f_pak(p, expo[i]+1); + //expo[i*p] = expo[i]+1; + pot[i*p] = pot[i] * p; + break; + } else { + f[i*p] = f[i] * f[p]; + pot[i*p] = p; + //expo[i*p] = 1; + } + } + } +} +``` diff --git a/content/docs/Matematica/cycleDetection.md b/content/docs/Matematica/cycleDetection.md new file mode 100644 index 0000000..61b4eb7 --- /dev/null +++ b/content/docs/Matematica/cycleDetection.md @@ -0,0 +1,51 @@ +--- +weight: 10 +title: "Deteccao de ciclo - Tortoise and Hare" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Linear no tanto que tem que andar pra ciclar, + + O(1) de memoria + + Retorna um par com o tanto que tem que andar + + do f0 ate o inicio do ciclo e o tam do ciclo + + + +Link original: [cycleDetection.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Matematica/cycleDetection.cpp) + +## Código +```cpp +pair find_cycle() { + ll tort = f(f0); + ll hare = f(f(f0)); + ll t = 0; + while (tort != hare) { + tort = f(tort); + hare = f(f(hare)); + t++; + } + ll st = 0; + tort = f0; + while (tort != hare) { + tort = f(tort); + hare = f(hare); + st++; + } + + ll len = 1; + hare = f(tort); + while (tort != hare) { + hare = f(hare); + len++; + } + return {st, len}; +} +``` diff --git a/content/docs/Matematica/diofantina.md b/content/docs/Matematica/diofantina.md new file mode 100644 index 0000000..e92cd0d --- /dev/null +++ b/content/docs/Matematica/diofantina.md @@ -0,0 +1,68 @@ +--- +weight: 10 +title: "Equacao Diofantina Linear" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Encontra o numero de solucoes de a*x + b*y = c, + + em que x \in [lx, rx] e y \in [ly, ry] + + Usar o comentario para recuperar as solucoes + + (note que o b ao final eh b/gcd(a, b)) + + Cuidado com overflow! Tem que caber o quadrado dos valores + + + + O(log(min(a, b))) + + + +Link original: [diofantina.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Matematica/diofantina.cpp) + +## Código +```cpp +template tuple ext_gcd(ll a, ll b) { + if (!a) return {b, 0, 1}; + auto [g, x, y] = ext_gcd(b%a, a); + return {g, y - b/a*x, x}; +} + +// numero de solucoes de a*[lx, rx] + b*[ly, ry] = c +template // usar __int128 se for ate 1e18 +ll diophantine(ll a, ll b, ll c, ll lx, ll rx, ll ly, ll ry) { + if (lx > rx or ly > ry) return 0; + if (a == 0 and b == 0) return c ? 0 : (rx-lx+1)*(ry-ly+1); + auto [g, x, y] = ext_gcd(abs(a), abs(b)); + if (c % g != 0) return 0; + if (a == 0) return (rx-lx+1)*(ly <= c/b and c/b <= ry); + if (b == 0) return (ry-ly+1)*(lx <= c/a and c/a <= rx); + x *= a/abs(a) * c/g, y *= b/abs(b) * c/g, a /= g, b /= g; + + auto shift = [&](T qt) { x += qt*b, y -= qt*a; }; + auto test = [&](T& k, ll mi, ll ma, ll coef, int t) { + shift((mi - k)*t / coef); + if (k < mi) shift(coef > 0 ? t : -t); + if (k > ma) return pair(rx+2, rx+1); + T x1 = x; + shift((ma - k)*t / coef); + if (k > ma) shift(coef > 0 ? -t : t); + return pair(x1, x); + }; + + auto [l1, r1] = test(x, lx, rx, b, 1); + auto [l2, r2] = test(y, ly, ry, a, -1); + if (l2 > r2) swap(l2, r2); + T l = max(l1, l2), r = min(r1, r2); + if (l > r) return 0; + ll k = (r-l) / abs(b) + 1; + return k; // solucoes: x = l + [0, k)*|b| +} +``` diff --git a/content/docs/Matematica/divisionTrick.md b/content/docs/Matematica/divisionTrick.md new file mode 100644 index 0000000..74b06af --- /dev/null +++ b/content/docs/Matematica/divisionTrick.md @@ -0,0 +1,26 @@ +--- +weight: 10 +title: "Division Trick" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Gera o conjunto n/i, pra todo i, em O(sqrt(n)) + + copiei do github do tfg50 + + + +Link original: [divisionTrick.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Matematica/divisionTrick.cpp) + +## Código +```cpp +for(int l = 1, r; l <= n; l = r + 1) { + r = n / (n / l); + // n / i has the same value for l <= i <= r +} +``` diff --git a/content/docs/Matematica/evalInterpol.md b/content/docs/Matematica/evalInterpol.md new file mode 100644 index 0000000..3459342 --- /dev/null +++ b/content/docs/Matematica/evalInterpol.md @@ -0,0 +1,50 @@ +--- +weight: 10 +title: "Avaliacao de Interpolacao" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Dado 'n' pontos (i, y[i]), i \in [0, n), + + avalia o polinomio de grau n-1 que passa + + por esses pontos em 'x' + + Tudo modular, precisa do mint + + + + O(n) + + + +Link original: [evalInterpol.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Matematica/evalInterpol.cpp) + +## Código +```cpp +mint evaluate_interpolation(int x, vector y) { + int n = y.size(); + + vector sulf(n+1, 1), fat(n, 1), ifat(n); + for (int i = n-1; i >= 0; i--) sulf[i] = sulf[i+1] * (x - i); + for (int i = 1; i < n; i++) fat[i] = fat[i-1] * i; + ifat[n-1] = 1/fat[n-1]; + for (int i = n-2; i >= 0; i--) ifat[i] = ifat[i+1] * (i + 1); + + mint pref = 1, ans = 0; + for (int i = 0; i < n; pref *= (x - i++)) { + mint num = pref * sulf[i+1]; + + mint den = ifat[i] * ifat[n-1 - i]; + if ((n-1 - i)%2) den *= -1; + + ans += y[i] * num * den; + } + return ans; +} +``` diff --git a/content/docs/Matematica/fastPow.md b/content/docs/Matematica/fastPow.md new file mode 100644 index 0000000..5449dec --- /dev/null +++ b/content/docs/Matematica/fastPow.md @@ -0,0 +1,35 @@ +--- +weight: 10 +title: "Exponenciacao rapida" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + (x^y mod m) em O(log(y)) + + + +Link original: [fastPow.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Matematica/fastPow.cpp) + +## Código +```cpp +ll pow(ll x, ll y, ll m) { // iterativo + ll ret = 1; + while (y) { + if (y & 1) ret = (ret * x) % m; + y >>= 1; + x = (x * x) % m; + } + return ret; +} + +ll pow(ll x, ll y, ll m) { // recursivo + if (!y) return 1; + ll ans = pow(x*x%m, y/2, m); + return y%2 ? x*ans%m : ans; +} +``` diff --git a/content/docs/Matematica/fwht.md b/content/docs/Matematica/fwht.md new file mode 100644 index 0000000..1f80321 --- /dev/null +++ b/content/docs/Matematica/fwht.md @@ -0,0 +1,96 @@ +--- +weight: 10 +title: "Fast Walsh Hadamard Transform" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + FWHT<'|'>(f) eh SOS DP + + FWHT<'&'>(f) eh soma de superset DP + + Se chamar com ^, usar tamanho potencia de 2!! + + + + O(n log(n)) + + + +Link original: [fwht.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Matematica/fwht.cpp) + +## Código +```cpp +template vector FWHT(vector f, bool inv = false) { + int n = f.size(); + for (int k = 0; (n-1)>>k; k++) for (int i = 0; i < n; i++) if (i>>k&1) { + int j = i^(1< +vector FWHT(vector f, int b, T g, bool inv = false) { + int n = f.size(); + + vector w(b); + w[1] = g; + for (int i = 2; i < b; i++) w[i] = w[i - 1] * g; + w[0] = w[b - 1] * g; + + if (inv) reverse(w.begin() + 1, w.end()); + + for (int pot = 1; pot < n; pot *= b) { + for (int i = 0; i < n; i++) if (!(i / pot % b)) { + vector res(b); + for (int j = 0; j < b; j++) { + for (int k = 0; k < b; k++) + res[j] = res[j] + w[j * k % b] * f[i + k * pot]; + if (inv) res[j] = res[j] / b; + } + for (int j = 0; j < b; j++) f[i + j * pot] = res[j]; + } + } + + return f; +} + +// Exemplos da FWHT Generalizada: +// +// mod 7, resposta mod 998244353: +// T = mint, g = 14553391 +// +// mod 3, resposta cabe em um long long: +// T = array, g = {0, 1}; +// +// using T = array; +// T operator +(const T& a, const T& b) { +// return T{a[0] + b[0], a[1] + b[1]}; +// } +// T operator *(const T& a, const T& b) { +// return T{a[0] * b[0] - a[1] * b[1], +// a[0] * b[1] + a[1] * b[0] - a[1] * b[1]}; +// }; +// T operator /(const T& a, const int& b) { +// return T{a[0] / b, a[1] / b}; +// } +``` diff --git a/content/docs/Matematica/gauss.md b/content/docs/Matematica/gauss.md new file mode 100644 index 0000000..3566f18 --- /dev/null +++ b/content/docs/Matematica/gauss.md @@ -0,0 +1,67 @@ +--- +weight: 10 +title: "Gauss" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Resolve sistema linear + + Retornar um par com o numero de solucoes + + e alguma solucao, caso exista + + + + O(n^2 * m) + + + +Link original: [gauss.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Matematica/gauss.cpp) + +## Código +```cpp +template +pair> gauss(vector> a, vector b) { + const double eps = 1e-6; + int n = a.size(), m = a[0].size(); + for (int i = 0; i < n; i++) a[i].push_back(b[i]); + + vector where(m, -1); + for (int col = 0, row = 0; col < m and row < n; col++) { + int sel = row; + for (int i=row; i abs(a[sel][col])) sel = i; + if (abs(a[sel][col]) < eps) continue; + for (int i = col; i <= m; i++) + swap(a[sel][i], a[row][i]); + where[col] = row; + + for (int i = 0; i < n; i++) if (i != row) { + T c = a[i][col] / a[row][col]; + for (int j = col; j <= m; j++) + a[i][j] -= a[row][j] * c; + } + row++; + } + + vector ans(m, 0); + for (int i = 0; i < m; i++) if (where[i] != -1) + ans[i] = a[where[i]][m] / a[where[i]][i]; + for (int i = 0; i < n; i++) { + T sum = 0; + for (int j = 0; j < m; j++) + sum += ans[j] * a[i][j]; + if (abs(sum - a[i][m]) > eps) + return pair(0, vector()); + } + + for (int i = 0; i < m; i++) if (where[i] == -1) + return pair(INF, ans); + return pair(1, ans); +} +``` diff --git a/content/docs/Matematica/gaussZ2.md b/content/docs/Matematica/gaussZ2.md new file mode 100644 index 0000000..e0444ce --- /dev/null +++ b/content/docs/Matematica/gaussZ2.md @@ -0,0 +1,72 @@ +--- +weight: 10 +title: "Gauss - Z2" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + D eh dimensao do espaco vetorial + + add(v) - adiciona o vetor v na base (retorna se ele jah pertencia ao span da base) + + coord(v) - retorna as coordenadas (c) de v na base atual (basis^T.c = v) + + recover(v) - retorna as coordenadas de v nos vetores na ordem em que foram inseridos + + coord(v).first e recover(v).first - se v pertence ao span + + + + Complexidade: + + add, coord, recover: O(D^2 / 64) + + + +Link original: [gaussZ2.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Matematica/gaussZ2.cpp) + +## Código +```cpp +template struct gauss_z2 { + bitset basis[D], keep[D]; + int rk, in; + vector id; + + gauss_z2 () : rk(0), in(-1), id(D, -1) {}; + + bool add(bitset v) { + in++; + bitset k; + for (int i = D - 1; i >= 0; i--) if (v[i]) { + if (basis[i][i]) v ^= basis[i], k ^= keep[i]; + else { + k[i] = true, id[i] = in, keep[i] = k; + basis[i] = v, rk++; + return true; + } + } + return false; + } + pair> coord(bitset v) { + bitset c; + for (int i = D - 1; i >= 0; i--) if (v[i]) { + if (basis[i][i]) v ^= basis[i], c[i] = true; + else return {false, bitset()}; + } + return {true, c}; + } + pair> recover(bitset v) { + auto [span, bc] = coord(v); + if (not span) return {false, {}}; + bitset aux; + for (int i = D - 1; i >= 0; i--) if (bc[i]) aux ^= keep[i]; + vector oc; + for (int i = D - 1; i >= 0; i--) if (aux[i]) oc.push_back(id[i]); + return {true, oc}; + } +}; +``` diff --git a/content/docs/Matematica/gcdEstendido.md b/content/docs/Matematica/gcdEstendido.md new file mode 100644 index 0000000..634a8fa --- /dev/null +++ b/content/docs/Matematica/gcdEstendido.md @@ -0,0 +1,31 @@ +--- +weight: 10 +title: "Euclides estendido" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Acha x e y tal que ax + by = mdc(a, b) (nao eh unico) + + Assume a, b >= 0 + + + + O(log(min(a, b))) + + + +Link original: [gcdEstendido.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Matematica/gcdEstendido.cpp) + +## Código +```cpp +tuple ext_gcd(ll a, ll b) { + if (!a) return {b, 0, 1}; + auto [g, x, y] = ext_gcd(b%a, a); + return {g, y - b/a*x, x}; +} +``` diff --git a/content/docs/Matematica/gcdLcmConvolution.md b/content/docs/Matematica/gcdLcmConvolution.md new file mode 100644 index 0000000..7cfc0f3 --- /dev/null +++ b/content/docs/Matematica/gcdLcmConvolution.md @@ -0,0 +1,54 @@ +--- +weight: 10 +title: "Convolucao de GCD / LCM" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + O(n log(n)) + + + + multiple_transform(a)[i] = \sum_d a[d * i] + +Link original: [gcdLcmConvolution.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Matematica/gcdLcmConvolution.cpp) + +## Código +```cpp +template void multiple_transform(vector& v, bool inv = false) { + vector I(v.size()-1); + iota(I.begin(), I.end(), 1); + if (inv) reverse(I.begin(), I.end()); + for (int i : I) for (int j = 2; i*j < v.size(); j++) + v[i] += (inv ? -1 : 1) * v[i*j]; +} + +// gcd_convolution(a, b)[k] = \sum_{gcd(i, j) = k} a_i * b_j +template vector gcd_convolution(vector a, vector b) { + multiple_transform(a), multiple_transform(b); + for (int i = 0; i < a.size(); i++) a[i] *= b[i]; + multiple_transform(a, true); + return a; +} + +// divisor_transform(a)[i] = \sum_{d|i} a[i/d] +template void divisor_transform(vector& v, bool inv = false) { + vector I(v.size()-1); + iota(I.begin(), I.end(), 1); + if (!inv) reverse(I.begin(), I.end()); + for (int i : I) for (int j = 2; i*j < v.size(); j++) + v[i*j] += (inv ? -1 : 1) * v[i]; +} + +// lcm_convolution(a, b)[k] = \sum_{lcm(i, j) = k} a_i * b_j +template vector lcm_convolution(vector a, vector b) { + divisor_transform(a), divisor_transform(b); + for (int i = 0; i < a.size(); i++) a[i] *= b[i]; + divisor_transform(a, true); + return a; +} +``` diff --git a/content/docs/Matematica/integral.md b/content/docs/Matematica/integral.md new file mode 100644 index 0000000..2e9c9f6 --- /dev/null +++ b/content/docs/Matematica/integral.md @@ -0,0 +1,28 @@ +--- +weight: 10 +title: "Integracao Numerica" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Metodo de Simpson 3/8 + + Integra f no intervalo [a, b], erro cresce proporcional a (b - a)^5 + + + +Link original: [integral.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Matematica/integral.cpp) + +## Código +```cpp +const int N = 3*100; // multiplo de 3 +ld integrate(ld a, ld b, function f) { + ld s = 0, h = (b - a)/N; + for (int i = 1 ; i < N; i++) s += f(a + i*h)*(i%3 ? 3 : 2); + return (f(a) + s + f(b))*3*h/8; +} +``` diff --git a/content/docs/Matematica/karatsuba.md b/content/docs/Matematica/karatsuba.md new file mode 100644 index 0000000..4c314ef --- /dev/null +++ b/content/docs/Matematica/karatsuba.md @@ -0,0 +1,61 @@ +--- +weight: 10 +title: "Karatsuba" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Os pragmas podem ajudar + + Para n ~ 2e5, roda em < 1 s + + + + O(n^1.58) + + + +#pragma GCC optimize("Ofast") + +#pragma GCC target ("avx,avx2") + +Link original: [karatsuba.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Matematica/karatsuba.cpp) + +## Código +```cpp +template void kar(T* a, T* b, int n, T* r, T* tmp) { + if (n <= 64) { + for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) + r[i+j] += a[i] * b[j]; + return; + } + int mid = n/2; + T *atmp = tmp, *btmp = tmp+mid, *E = tmp+n; + memset(E, 0, sizeof(E[0])*n); + for (int i = 0; i < mid; i++) { + atmp[i] = a[i] + a[i+mid]; + btmp[i] = b[i] + b[i+mid]; + } + kar(atmp, btmp, mid, E, tmp+2*n); + kar(a, b, mid, r, tmp+2*n); + kar(a+mid, b+mid, mid, r+n, tmp+2*n); + for (int i = 0; i < mid; i++) { + T temp = r[i+mid]; + r[i+mid] += E[i] - r[i] - r[i+2*mid]; + r[i+2*mid] += E[i+mid] - temp - r[i+3*mid]; + } +} + +template vector karatsuba(vector a, vector b) { + int n = max(a.size(), b.size()); + while (n&(n-1)) n++; + a.resize(n), b.resize(n); + vector ret(2*n), tmp(4*n); + kar(&a[0], &b[0], n, &ret[0], &tmp[0]); + return ret; +} +``` diff --git a/content/docs/Matematica/logDiscreto.md b/content/docs/Matematica/logDiscreto.md new file mode 100644 index 0000000..265150f --- /dev/null +++ b/content/docs/Matematica/logDiscreto.md @@ -0,0 +1,61 @@ +--- +weight: 10 +title: "Logaritmo Discreto" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Resolve logaritmo discreto com o algoritmo baby step giant step + + Encontra o menor x tal que a^x = b (mod m) + + Se nao tem, retorna -1 + + + + O(sqrt(m) * log(sqrt(m)) + +Link original: [logDiscreto.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Matematica/logDiscreto.cpp) + +## Código +```cpp + +int dlog(int b, int a, int m) { + if (a == 0) return b ? -1 : 1; // caso nao definido + + a %= m, b %= m; + int k = 1, shift = 0; + while (1) { + int g = gcd(a, m); + if (g == 1) break; + + if (b == k) return shift; + if (b % g) return -1; + b /= g, m /= g, shift++; + k = (ll) k * a / g % m; + } + + int sq = sqrt(m)+1, giant = 1; + for (int i = 0; i < sq; i++) giant = (ll) giant * a % m; + + vector> baby; + for (int i = 0, cur = b; i <= sq; i++) { + baby.emplace_back(cur, i); + cur = (ll) cur * a % m; + } + sort(baby.begin(), baby.end()); + + for (int j = 1, cur = k; j <= sq; j++) { + cur = (ll) cur * giant % m; + auto it = lower_bound(baby.begin(), baby.end(), pair(cur, INF)); + if (it != baby.begin() and (--it)->first == cur) + return sq * j - it->second + shift; + } + + return -1; +} +``` diff --git a/content/docs/Matematica/millerRabin.md b/content/docs/Matematica/millerRabin.md new file mode 100644 index 0000000..689d004 --- /dev/null +++ b/content/docs/Matematica/millerRabin.md @@ -0,0 +1,57 @@ +--- +weight: 10 +title: "Miller-Rabin" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Testa se n eh primo, n <= 3 * 10^18 + + + + O(log(n)), considerando multiplicacao + + e exponenciacao constantes + + + +Link original: [millerRabin.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Matematica/millerRabin.cpp) + +## Código +```cpp +ll mul(ll a, ll b, ll m) { + ll ret = a*b - ll((long double)1/m*a*b+0.5)*m; + return ret < 0 ? ret+m : ret; +} + +ll pow(ll x, ll y, ll m) { + if (!y) return 1; + ll ans = pow(mul(x, x, m), y/2, m); + return y%2 ? mul(x, ans, m) : ans; +} + +bool prime(ll n) { + if (n < 2) return 0; + if (n <= 3) return 1; + if (n % 2 == 0) return 0; + ll r = __builtin_ctzll(n - 1), d = n >> r; + + // com esses primos, o teste funciona garantido para n <= 2^64 + // funciona para n <= 3*10^24 com os primos ate 41 + for (int a : {2, 325, 9375, 28178, 450775, 9780504, 1795265022}) { + ll x = pow(a, d, n); + if (x == 1 or x == n - 1 or a % n == 0) continue; + + for (int j = 0; j < r - 1; j++) { + x = mul(x, x, n); + if (x == n - 1) break; + } + if (x != n - 1) return 0; + } + return 1; +} +``` diff --git a/content/docs/Matematica/modInverse.md b/content/docs/Matematica/modInverse.md new file mode 100644 index 0000000..068639e --- /dev/null +++ b/content/docs/Matematica/modInverse.md @@ -0,0 +1,32 @@ +--- +weight: 10 +title: "Inverso Modular" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Computa o inverso de a modulo b + + Se b eh primo, basta fazer + + a^(b-2) + + + +Link original: [modInverse.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Matematica/modInverse.cpp) + +## Código +```cpp +ll inv(ll a, ll b) { + return a > 1 ? b - inv(b%a, a)*b/a : 1; +} + +// computa o inverso modular de 1..MAX-1 modulo um primo +ll inv[MAX]: +inv[1] = 1; +for (int i = 2; i < MAX; i++) inv[i] = MOD - MOD/i*inv[MOD%i]%MOD; +``` diff --git a/content/docs/Matematica/mulmod.md b/content/docs/Matematica/mulmod.md new file mode 100644 index 0000000..b15372d --- /dev/null +++ b/content/docs/Matematica/mulmod.md @@ -0,0 +1,24 @@ +--- +weight: 10 +title: "Produto de dois long long mod m" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + O(1) + + + +Link original: [mulmod.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Matematica/mulmod.cpp) + +## Código +```cpp +ll mul(ll a, ll b, ll m) { // a*b % m + ll ret = a*b - ll((long double)1/m*a*b+0.5)*m; + return ret < 0 ? ret+m : ret; +} +``` diff --git a/content/docs/Matematica/multipointEvaluation.md b/content/docs/Matematica/multipointEvaluation.md new file mode 100644 index 0000000..2769213 --- /dev/null +++ b/content/docs/Matematica/multipointEvaluation.md @@ -0,0 +1,86 @@ +--- +weight: 10 +title: "Multipoint Evaluation And Interpolation" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Evaluation: + + Avalia o polinomio f(x) nos pontos p[0], p[1], ..., p[n-1] + + + + Interpolation: + + Retorna o polinomio f(x) de grau n que + + satisfaz f(x) = y pra o conjunto de pontos x, y + + + + Precisa do ntt e + + - do divmod pro evaluate + + - da derivada pro interpolate + + + + O divmod e a derivada estao no arquivo powerSeries.cpp + + + + O(n log^2(n)) + + + +Link original: [multipointEvaluation.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Matematica/multipointEvaluation.cpp) + +## Código +```cpp +namespace multipoint { + vector tree; + void build(vector& p) { + int n = p.size(); + tree.resize(2*n); + for (int i = 0; i < n; i++) tree[n + i] = {-p[i], 1}; + for (int i = n - 1; i > 0; i--) + tree[i] = convolution(tree[2*i], tree[2*i + 1]); + } + vector evaluate(poly& f, vector& p) { + build(p); + int n = p.size(); + vector ans(2 * n); + ans[1] = divmod(f, tree[1]).second; + for (int i = 2; i < 2 * n; i++) + ans[i] = divmod(ans[i/2], tree[i]).second; + vector results(n); + for (int i = 0; i < n; i++) results[i] = ans[n + i][0]; + return results; + } + poly prod(vector& p, int l, int r) { + if (l == r) return {-p[l], 1}; + int m = (l + r) / 2; + return convolution(prod(p, l, m), prod(p, m + 1, r)); + } + poly interpolate(vector& x, vector& y) { + int n = x.size(); + poly p = D(prod(x, 0, n - 1)); + auto d = evaluate(p, x); + vector ans(2 * n); + for (int i = 0; i < n; i++) ans[n + i] = {y[i] / d[i]}; + for (int i = n - 1; i > 0; i--) { + poly p1 = convolution(tree[2*i], ans[2*i + 1]); + poly p2 = convolution(tree[2*i + 1], ans[2*i]); + ans[i] = p1; + for (int j = 0; j < p1.size(); j++) ans[i][j] += p2[j]; + } + return ans[1]; + } +} +``` diff --git a/content/docs/Matematica/ntt.md b/content/docs/Matematica/ntt.md new file mode 100644 index 0000000..671ad0b --- /dev/null +++ b/content/docs/Matematica/ntt.md @@ -0,0 +1,64 @@ +--- +weight: 10 +title: "NTT" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Precisa do mint (primitivas de aritmetica modular) + + + + O(n log (n)) + + + +Link original: [ntt.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Matematica/ntt.cpp) + +## Código +```cpp +const int MOD = 998244353; +typedef mod_int mint; + +void ntt(vector& a, bool rev) { + int n = a.size(); auto b = a; + assert(!(n&(n-1))); + mint g = 1; + while ((g^(MOD / 2)) == 1) g += 1; + if (rev) g = 1 / g; + + for (int step = n / 2; step; step /= 2) { + mint w = g^(MOD / (n / step)), wn = 1; + for (int i = 0; i < n/2; i += step) { + for (int j = 0; j < step; j++) { + auto u = a[2 * i + j], v = wn * a[2 * i + j + step]; + b[i+j] = u + v; b[i + n/2 + j] = u - v; + } + wn = wn * w; + } + swap(a, b); + } + if (rev) { + auto n1 = mint(1) / n; + for (auto& x : a) x *= n1; + } +} + +vector convolution(const vector& a, const vector& b) { + vector l(a.begin(), a.end()), r(b.begin(), b.end()); + int N = l.size()+r.size()-1, n = 1; + while (n <= N) n *= 2; + l.resize(n); + r.resize(n); + ntt(l, false); + ntt(r, false); + for (int i = 0; i < n; i++) l[i] *= r[i]; + ntt(l, true); + l.resize(N); + return l; +} +``` diff --git a/content/docs/Matematica/pollardrho.md b/content/docs/Matematica/pollardrho.md new file mode 100644 index 0000000..8b58941 --- /dev/null +++ b/content/docs/Matematica/pollardrho.md @@ -0,0 +1,89 @@ +--- +weight: 10 +title: "Pollard's Rho Alg" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Usa o algoritmo de deteccao de ciclo de Floyd + + com uma otimizacao na qual o gcd eh acumulado + + A fatoracao nao sai necessariamente ordenada + + O algoritmo rho encontra um fator de n, + + e funciona muito bem quando n possui um fator pequeno + + + + Complexidades (considerando mul constante): + + rho - esperado O(n^(1/4)) no pior caso + + fact - esperado menos que O(n^(1/4) log(n)) no pior caso + + + +Link original: [pollardrho.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Matematica/pollardrho.cpp) + +## Código +```cpp +ll mul(ll a, ll b, ll m) { + ll ret = a*b - ll((long double)1/m*a*b+0.5)*m; + return ret < 0 ? ret+m : ret; +} + +ll pow(ll x, ll y, ll m) { + if (!y) return 1; + ll ans = pow(mul(x, x, m), y/2, m); + return y%2 ? mul(x, ans, m) : ans; +} + +bool prime(ll n) { + if (n < 2) return 0; + if (n <= 3) return 1; + if (n % 2 == 0) return 0; + + ll r = __builtin_ctzll(n - 1), d = n >> r; + for (int a : {2, 325, 9375, 28178, 450775, 9780504, 1795265022}) { + ll x = pow(a, d, n); + if (x == 1 or x == n - 1 or a % n == 0) continue; + + for (int j = 0; j < r - 1; j++) { + x = mul(x, x, n); + if (x == n - 1) break; + } + if (x != n - 1) return 0; + } + return 1; +} + +ll rho(ll n) { + if (n == 1 or prime(n)) return n; + auto f = [n](ll x) {return mul(x, x, n) + 1;}; + + ll x = 0, y = 0, t = 30, prd = 2, x0 = 1, q; + while (t % 40 != 0 or gcd(prd, n) == 1) { + if (x==y) x = ++x0, y = f(x); + q = mul(prd, abs(x-y), n); + if (q != 0) prd = q; + x = f(x), y = f(f(y)), t++; + } + return gcd(prd, n); +} + +vector fact(ll n) { + if (n == 1) return {}; + if (prime(n)) return {n}; + ll d = rho(n); + vector l = fact(d), r = fact(n / d); + l.insert(l.end(), r.begin(), r.end()); + return l; +} + +``` diff --git a/content/docs/Matematica/powerSeries.md b/content/docs/Matematica/powerSeries.md new file mode 100644 index 0000000..ec0c28c --- /dev/null +++ b/content/docs/Matematica/powerSeries.md @@ -0,0 +1,128 @@ +--- +weight: 10 +title: "Operacoes em Polinomios e Series de Potencias" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Precisa do NTT + + O exp nao foi bem testado + + + + Fonte: github.com/celiopassos/competitive-programming/blob/master/algorithms/mathematics/formal_power_series.hpp + + + + D, I: O(n) + + inv, divmod, log e exp: O(n log(n)) + + + +Link original: [powerSeries.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Matematica/powerSeries.cpp) + +## Código +```cpp +using poly = vector; + +const int MAGIC = 512; + +poly D(poly p) { + if (p.empty()) return p; + for (int i = 0; i + 1 < p.size(); i++) + p[i] = (i + 1) * p[i + 1]; + p.pop_back(); + return p; +} + +poly I(poly p) { + int n = p.size(); + p.push_back(0); + for (int i = n - 1; i >= 0; i--) + p[i + 1] = p[i] / (i + 1); + p[0] = 0; + return p; +} + +poly inv(poly p) { + assert(!p.empty() && p[0] == 1); + poly q = {mint(1) / p[0]}; + int n = p.size(), k = 1; + while (k < n) { + k *= 2; + q.resize(2 * k); + ntt(q, false); + poly p0(2 * k); + copy_n(p.begin(), min(k, n), p0.begin()); + ntt(p0, false); + for (int i = 0; i < 2 * k; i++) + q[i] *= 2 - p0[i] * q[i]; + ntt(q, true); + q.resize(k); + } + q.resize(n); + return q; +} + +pair divslow(const poly& a, const poly& b) { + poly q, r = a; + while (r.size() >= b.size()) { + q.push_back(r.back() / b.back()); + if (q.back() != 0) + for (int i = 0; i < b.size(); i++) + r.end()[-i-1] -= q.back() * b.end()[-i-1]; + r.pop_back(); + } + reverse(q.begin(), q.end()); + return {q, r}; +} + +// retorna (q, r) : a(x) = b(x) * q(x) + r(x) +pair divmod(const poly& a, const poly& b) { + if (a.size() < b.size()) return {{}, a}; + if (max(b.size(), a.size() - b.size()) < MAGIC) return divslow(a, b); + poly ra = poly(a.rbegin(), a.rend()); + poly rb = poly(b.rbegin(), b.rend()); + int k = a.size() - b.size() + 1; + rb.resize(k); + poly irb = inv(move(rb)), q = convolution(ra, irb); + q = poly(q.rend() - k, q.rend()); + poly r = convolution(move(q), b); + for (int i = 0; i < r.size(); i++) r[i] = a[i] - r[i]; + while (r.size() > 1 && r.back() == 0) r.pop_back(); + return {q, r}; +} + +poly log(poly p) { + assert(!p.empty() && p[0] == 1); + int n = p.size(); + auto d = D(p), i = inv(p); + auto r = convolution(d, i); + r.resize(n - 1); + return I(move(r)); +} + +poly exp(poly p) { + assert(p.empty() || p[0] == 0); + poly q = {1}; + int n = p.size(), k = 1; + while (k < n) { + k *= 2; + q.resize(k); + poly b = log(q); + for (int i = 0; i < k; i++) b[i] *= -1; + b[0] += 1; + for (int i = 0; i < min(n, k); i++) b[i] += p[i]; + q = convolution(q, b); + q.resize(k); + } + q.resize(n); + return q; +} +``` diff --git a/content/docs/Matematica/probabilityBinomial.md b/content/docs/Matematica/probabilityBinomial.md new file mode 100644 index 0000000..e3978fc --- /dev/null +++ b/content/docs/Matematica/probabilityBinomial.md @@ -0,0 +1,32 @@ +--- +weight: 10 +title: "Binomial Distribution" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + binom(n, k, p) retorna a probabilidade de k sucessos + + numa binomial(n, p) + + + +Link original: [probabilityBinomial.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Matematica/probabilityBinomial.cpp) + +## Código +```cpp +double logfact[MAX]; + +void calc() { + logfact[0] = 0; + for (int i = 1; i < MAX; i++) logfact[i] = logfact[i-1] + log(i); +} + +double binom(int n, int k, double p) { + return exp(logfact[n] - logfact[k] - logfact[n-k] + k * log(p) + (n-k) * log(1 - p)); +} +``` diff --git a/content/docs/Matematica/simplex.md b/content/docs/Matematica/simplex.md new file mode 100644 index 0000000..949468d --- /dev/null +++ b/content/docs/Matematica/simplex.md @@ -0,0 +1,82 @@ +--- +weight: 10 +title: "Simplex" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Maximiza c^T x s.t. Ax <= b, x >= 0 + + + + O(2^n), porem executa em O(n^3) no caso medio + + + +Link original: [simplex.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Matematica/simplex.cpp) + +## Código +```cpp +const double eps = 1e-7; + +namespace Simplex { + vector> T; + int n, m; + vector X, Y; + + void pivot(int x, int y) { + swap(X[y], Y[x-1]); + for (int i = 0; i <= m; i++) if (i != y) T[x][i] /= T[x][y]; + T[x][y] = 1/T[x][y]; + for (int i = 0; i <= n; i++) if (i != x and abs(T[i][y]) > eps) { + for (int j = 0; j <= m; j++) if (j != y) T[i][j] -= T[i][y] * T[x][j]; + T[i][y] = -T[i][y] * T[x][y]; + } + } + + // Retorna o par (valor maximo, vetor solucao) + pair> simplex( + vector> A, vector b, vector c) { + n = b.size(), m = c.size(); + T = vector(n + 1, vector(m + 1)); + X = vector(m); + Y = vector(n); + for (int i = 0; i < m; i++) X[i] = i; + for (int i = 0; i < n; i++) Y[i] = i+m; + for (int i = 0; i < m; i++) T[0][i] = -c[i]; + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) T[i+1][j] = A[i][j]; + T[i+1][m] = b[i]; + } + while (true) { + int x = -1, y = -1; + double mn = -eps; + for (int i = 1; i <= n; i++) if (T[i][m] < mn) mn = T[i][m], x = i; + if (x < 0) break; + for (int i = 0; i < m; i++) if (T[x][i] < -eps) { y = i; break; } + + if (y < 0) return {-1e18, {}}; // sem solucao para Ax <= b + pivot(x, y); + } + while (true) { + int x = -1, y = -1; + double mn = -eps; + for (int i = 0; i < m; i++) if (T[0][i] < mn) mn = T[0][i], y = i; + if (y < 0) break; + mn = 1e200; + for (int i = 1; i <= n; i++) if (T[i][y] > eps and T[i][m] / T[i][y] < mn) + mn = T[i][m] / T[i][y], x = i; + + if (x < 0) return {1e18, {}}; // c^T x eh ilimitado + pivot(x, y); + } + vector r(m); + for(int i = 0; i < n; i++) if (Y[i] < m) r[Y[i]] = T[i+1][m]; + return {T[0][m], r}; + } +} +``` diff --git a/content/docs/Matematica/totiente.md b/content/docs/Matematica/totiente.md new file mode 100644 index 0000000..8e87af4 --- /dev/null +++ b/content/docs/Matematica/totiente.md @@ -0,0 +1,31 @@ +--- +weight: 10 +title: "Totiente" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + O(sqrt(n)) + + + +Link original: [totiente.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Matematica/totiente.cpp) + +## Código +```cpp +int tot(int n){ + int ret = n; + + for (int i = 2; i*i <= n; i++) if (n % i == 0) { + while (n % i == 0) n /= i; + ret -= ret / i; + } + if (n > 1) ret -= ret / n; + + return ret; +} +``` diff --git a/content/docs/Primitivas/_index.md b/content/docs/Primitivas/_index.md new file mode 100644 index 0000000..7754b7a --- /dev/null +++ b/content/docs/Primitivas/_index.md @@ -0,0 +1,8 @@ +--- +weight: 10 +title: "Primitivas" +draft: false +date: "2024-05-09T17:19:25-0300" +description: "" +publishdate: "2024-05-09T17:19:25-0300" +--- diff --git a/content/docs/Primitivas/bigint.md b/content/docs/Primitivas/bigint.md new file mode 100644 index 0000000..131ef21 --- /dev/null +++ b/content/docs/Primitivas/bigint.md @@ -0,0 +1,278 @@ +--- +weight: 10 +title: "Big Integer" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Complexidades: (para n digitos) + + Soma, subtracao, comparacao - O(n) + + Multiplicacao - O(n log(n)) + + Divisao, resto - O(n^2) + + + +Link original: [bigint.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Primitivas/bigint.cpp) + +## Código +```cpp +struct bint { + static const int BASE = 1e9; + vector v; + bool neg; + + bint() : neg(0) {} + bint(int val) : bint() { *this = val; } + bint(long long val) : bint() { *this = val; } + + void trim() { + while (v.size() and v.back() == 0) v.pop_back(); + if (!v.size()) neg = 0; + } + + // converter de/para string | cin/cout + bint(const char* s) : bint() { from_string(string(s)); } + bint(const string& s) : bint() { from_string(s); } + void from_string(const string& s) { + v.clear(), neg = 0; + int ini = 0; + while (ini < s.size() and (s[ini] == '-' or s[ini] == '+' or s[ini] == '0')) + if (s[ini++] == '-') neg = 1; + for (int i = s.size()-1; i >= ini; i -= 9) { + int at = 0; + for (int j = max(ini, i - 8); j <= i; j++) at = 10*at + (s[j]-'0'); + v.push_back(at); + } + if (!v.size()) neg = 0; + } + string to_string() const { + if (!v.size()) return "0"; + string ret; + if (neg) ret += '-'; + for (int i = v.size()-1; i >= 0; i--) { + string at = ::to_string(v[i]); + int add = 9 - at.size(); + if (i+1 < v.size()) for (int j = 0; j < add; j++) ret += '0'; + ret += at; + } + return ret; + } + friend istream& operator>>(istream& in, bint& val) { + string s; in >> s; + val = s; + return in; + } + friend ostream& operator<<(ostream& out, const bint& val) { + string s = val.to_string(); + out << s; + return out; + } + + // operators + friend bint abs(bint val) { + val.neg = 0; + return val; + } + friend bint operator-(bint val) { + if (val != 0) val.neg ^= 1; + return val; + } + bint& operator=(const bint& val) { v = val.v, neg = val.neg; return *this; } + bint& operator=(long long val) { + v.clear(), neg = 0; + if (val < 0) neg = 1, val *= -1; + for (; val; val /= BASE) v.push_back(val % BASE); + return *this; + } + int cmp(const bint& r) const { // menor: -1 | igual: 0 | maior: 1 + if (neg != r.neg) return neg ? -1 : 1; + if (v.size() != r.v.size()) { + int ret = v.size() < r.v.size() ? -1 : 1; + return neg ? -ret : ret; + } + for (int i = int(v.size())-1; i >= 0; i--) { + if (v[i] != r.v[i]) { + int ret = v[i] < r.v[i] ? -1 : 1; + return neg ? -ret : ret; + } + } + return 0; + } + friend bool operator<(const bint& l, const bint& r) { return l.cmp(r) == -1; } + friend bool operator>(const bint& l, const bint& r) { return l.cmp(r) == 1; } + friend bool operator<=(const bint& l, const bint& r) { return l.cmp(r) <= 0; } + friend bool operator>=(const bint& l, const bint& r) { return l.cmp(r) >= 0; } + friend bool operator==(const bint& l, const bint& r) { return l.cmp(r) == 0; } + friend bool operator!=(const bint& l, const bint& r) { return l.cmp(r) != 0; } + + bint& operator +=(const bint& r) { + if (!r.v.size()) return *this; + if (neg != r.neg) return *this -= -r; + for (int i = 0, c = 0; i < r.v.size() or c; i++) { + if (i == v.size()) v.push_back(0); + v[i] += c + (i < r.v.size() ? r.v[i] : 0); + if ((c = v[i] >= BASE)) v[i] -= BASE; + } + return *this; + } + friend bint operator+(bint a, const bint& b) { return a += b; } + bint& operator -=(const bint& r) { + if (!r.v.size()) return *this; + if (neg != r.neg) return *this += -r; + if ((!neg and *this < r) or (neg and r < *this)) { + *this = r - *this; + neg ^= 1; + return *this; + } + for (int i = 0, c = 0; i < r.v.size() or c; i++) { + v[i] -= c + (i < r.v.size() ? r.v[i] : 0); + if ((c = v[i] < 0)) v[i] += BASE; + } + trim(); + return *this; + } + friend bint operator-(bint a, const bint& b) { return a -= b; } + + // operators de * / % + bint& operator *=(int val) { + if (val < 0) val *= -1, neg ^= 1; + for (int i = 0, c = 0; i < v.size() or c; i++) { + if (i == v.size()) v.push_back(0); + long long at = (long long) v[i] * val + c; + v[i] = at % BASE; + c = at / BASE; + } + trim(); + return *this; + } + friend bint operator *(bint a, int b) { return a *= b; } + friend bint operator *(int a, bint b) { return b *= a; } + using cplx = complex; + void fft(vector& a, bool f, int N, vector& rev) const { + for (int i = 0; i < N; i++) if (i < rev[i]) swap(a[i], a[rev[i]]); + vector roots(N); + for (int n = 2; n <= N; n *= 2) { + const static double PI = acos(-1); + for (int i = 0; i < n/2; i++) { + double alpha = (2*PI*i)/n; + if (f) alpha = -alpha; + roots[i] = cplx(cos(alpha), sin(alpha)); + } + for (int pos = 0; pos < N; pos += n) + for (int l = pos, r = pos+n/2, m = 0; m < n/2; l++, r++, m++) { + auto t = roots[m]*a[r]; + a[r] = a[l] - t; + a[l] = a[l] + t; + } + } + if (!f) return; + auto invN = cplx(1)/cplx(N); + for (int i = 0; i < N; i++) a[i] *= invN; + } + vector convolution(const vector& a, const vector& b) const { + vector l(a.begin(), a.end()), r(b.begin(), b.end()); + int ln = l.size(), rn = r.size(), N = ln+rn+1, n = 1, log_n = 0; + while (n <= N) n <<= 1, log_n++; + vector rev(n); + for (int i = 0; i < n; i++) { + rev[i] = 0; + for (int j = 0; j < log_n; j++) if (i>>j&1) + rev[i] |= 1 << (log_n-1-j); + } + l.resize(n), r.resize(n); + fft(l, false, n, rev), fft(r, false, n, rev); + for (int i = 0; i < n; i++) l[i] *= r[i]; + fft(l, true, n, rev); + vector ret; + for (auto& i : l) ret.push_back(round(i.real())); + return ret; + } + vector convert_base(const vector& a, int from, int to) const { + static vector pot(10, 1); + if (pot[1] == 1) for (int i = 1; i < 10; i++) pot[i] = 10*pot[i-1]; + vector ret; + long long at = 0; + int digits = 0; + for (int i : a) { + at += i * pot[digits]; + digits += from; + while (digits >= to) { + ret.push_back(at % pot[to]); + at /= pot[to]; + digits -= to; + } + } + ret.push_back(at); + while (ret.size() and ret.back() == 0) ret.pop_back(); + return ret; + } + bint operator*(const bint& r) const { // O(n log(n)) + bint ret; + ret.neg = neg ^ r.neg; + auto conv = convolution(convert_base(v, 9, 4), convert_base(r.v, 9, 4)); + long long c = 0; + for (auto i : conv) { + long long at = i+c; + ret.v.push_back(at % 10000); + c = at / 10000; + } + for (; c; c /= 10000) ret.v.push_back(c%10000); + ret.v = convert_base(ret.v, 4, 9); + if (!ret.v.size()) ret.neg = 0; + return ret; + } + bint& operator*=(const bint& r) { return *this = *this * r; }; + bint& operator/=(int val) { + if (val < 0) neg ^= 1, val *= -1; + for (int i = int(v.size())-1, c = 0; i >= 0; i--) { + long long at = v[i] + c * (long long) BASE; + v[i] = at / val; + c = at % val; + } + trim(); + return *this; + } + friend bint operator/(bint a, int b) { return a /= b; } + int operator %=(int val) { + if (val < 0) val *= -1; + long long at = 0; + for (int i = int(v.size())-1; i >= 0; i--) + at = (BASE * at + v[i]) % val; + if (neg) at *= -1; + return at; + } + friend int operator%(bint a, int b) { return a %= b; } + friend pair divmod(const bint& a_, const bint& b_) { // O(n^2) + if (a_ == 0) return {0, 0}; + int norm = BASE / (b_.v.back() + 1); + bint a = abs(a_) * norm; + bint b = abs(b_) * norm; + bint q, r; + for (int i = a.v.size() - 1; i >= 0; i--) { + r *= BASE, r += a.v[i]; + long long upper = b.v.size() < r.v.size() ? r.v[b.v.size()] : 0; + int lower = b.v.size() - 1 < r.v.size() ? r.v[b.v.size() - 1] : 0; + int d = (upper * BASE + lower) / b.v.back(); + r -= b*d; + while (r < 0) r += b, d--; // roda O(1) vezes + q.v.push_back(d); + } + reverse(q.v.begin(), q.v.end()); + q.neg = a_.neg ^ b_.neg; + r.neg = a_.neg; + q.trim(), r.trim(); + return {q, r / norm}; + } + bint operator/(const bint& val) { return divmod(*this, val).first; } + bint& operator/=(const bint& val) { return *this = *this / val; } + bint operator%(const bint& val) { return divmod(*this, val).second; } + bint& operator%=(const bint& val) { return *this = *this % val; } +}; +``` diff --git a/content/docs/Primitivas/calendario.md b/content/docs/Primitivas/calendario.md new file mode 100644 index 0000000..c9eeb07 --- /dev/null +++ b/content/docs/Primitivas/calendario.md @@ -0,0 +1,41 @@ +--- +weight: 10 +title: "Calendario" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Congruencia de Zeller + + + + Os dias da semana correspondem aos restos % 7 + + Segunda=0, Terca=1, ..., Domingo=6 + + + +Link original: [calendario.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Primitivas/calendario.cpp) + +## Código +```cpp +int get_id(int d, int m, int y) { + if (m < 3) y--, m += 12; + return 365 * y + y / 4 - y / 100 + y / 400 + (153 * (m - 3) + 2) / 5 + d - 307; +} + +tuple date(int id) { + int x = id + 1789995, n = 4 * x / 146097, i, j, d, m, y; + x -= (146097 * n + 3) / 4; + i = (4000 * (x + 1)) / 1461001; + x -= 1461 * i / 4 - 31; + j = 80 * x / 2447, d = x - 2447 * j / 80; + x = j / 11; + m = j + 2 - 12 * x, y = 100 * (n - 49) + i + x; + return {d, m, y}; +} +``` diff --git a/content/docs/Primitivas/frac.md b/content/docs/Primitivas/frac.md new file mode 100644 index 0000000..7a7d8c4 --- /dev/null +++ b/content/docs/Primitivas/frac.md @@ -0,0 +1,50 @@ +--- +weight: 10 +title: "Fracao" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Funciona com o Big Int + + + +Link original: [frac.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Primitivas/frac.cpp) + +## Código +```cpp +template struct frac { + T num, den; + template + frac(U num_ = 0, V den_ = 1) : num(num_), den(den_) { + assert(den != 0); + if (den < 0) num *= -1, den *= -1; + T g = gcd(abs(num), den); + num /= g, den /= g; + } + + friend bool operator<(const frac& l, const frac& r) { + return l.num * r.den < r.num * l.den; + } + friend frac operator+(const frac& l, const frac& r) { + return {l.num*r.den + l.den*r.num, l.den*r.den}; + } + friend frac operator-(const frac& l, const frac& r) { + return {l.num*r.den - l.den*r.num, l.den*r.den}; + } + friend frac operator*(const frac& l, const frac& r) { + return {l.num*r.num, l.den*r.den}; + } + friend frac operator/(const frac& l, const frac& r) { + return {l.num*r.den, l.den*r.num}; + } + friend ostream& operator<<(ostream& out, frac f) { + out << f.num << '/' << f.den; + return out; + } +}; +``` diff --git a/content/docs/Primitivas/geometria.md b/content/docs/Primitivas/geometria.md new file mode 100644 index 0000000..56e4cce --- /dev/null +++ b/content/docs/Primitivas/geometria.md @@ -0,0 +1,369 @@ +--- +weight: 10 +title: "Geometria" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre +Link original: [geometria.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Primitivas/geometria.cpp) + +## Código +```cpp +typedef double ld; +const ld DINF = 1e18; +const ld pi = acos(-1.0); +const ld eps = 1e-9; + +#define sq(x) ((x)*(x)) + +bool eq(ld a, ld b) { + return abs(a - b) <= eps; +} + +struct pt { // ponto + ld x, y; + pt(ld x_ = 0, ld y_ = 0) : x(x_), y(y_) {} + bool operator < (const pt p) const { + if (!eq(x, p.x)) return x < p.x; + if (!eq(y, p.y)) return y < p.y; + return 0; + } + bool operator == (const pt p) const { + return eq(x, p.x) and eq(y, p.y); + } + pt operator + (const pt p) const { return pt(x+p.x, y+p.y); } + pt operator - (const pt p) const { return pt(x-p.x, y-p.y); } + pt operator * (const ld c) const { return pt(x*c , y*c ); } + pt operator / (const ld c) const { return pt(x/c , y/c ); } + ld operator * (const pt p) const { return x*p.x + y*p.y; } + ld operator ^ (const pt p) const { return x*p.y - y*p.x; } + friend istream& operator >> (istream& in, pt& p) { + return in >> p.x >> p.y; + } +}; + +struct line { // reta + pt p, q; + line() {} + line(pt p_, pt q_) : p(p_), q(q_) {} + friend istream& operator >> (istream& in, line& r) { + return in >> r.p >> r.q; + } +}; + +// PONTO & VETOR + +ld dist(pt p, pt q) { // distancia + return hypot(p.y - q.y, p.x - q.x); +} + +ld dist2(pt p, pt q) { // quadrado da distancia + return sq(p.x - q.x) + sq(p.y - q.y); +} + +ld norm(pt v) { // norma do vetor + return dist(pt(0, 0), v); +} + +ld angle(pt v) { // angulo do vetor com o eixo x + ld ang = atan2(v.y, v.x); + if (ang < 0) ang += 2*pi; + return ang; +} + +ld sarea(pt p, pt q, pt r) { // area com sinal + return ((q-p)^(r-q))/2; +} + +bool col(pt p, pt q, pt r) { // se p, q e r sao colin. + return eq(sarea(p, q, r), 0); +} + +bool ccw(pt p, pt q, pt r) { // se p, q, r sao ccw + return sarea(p, q, r) > eps; +} + +pt rotate(pt p, ld th) { // rotaciona o ponto th radianos + return pt(p.x * cos(th) - p.y * sin(th), + p.x * sin(th) + p.y * cos(th)); +} + +pt rotate90(pt p) { // rotaciona 90 graus + return pt(-p.y, p.x); +} + +// RETA + +bool isvert(line r) { // se r eh vertical + return eq(r.p.x, r.q.x); +} + +bool isinseg(pt p, line r) { // se p pertence ao seg de r + pt a = r.p - p, b = r.q - p; + return eq((a ^ b), 0) and (a * b) < eps; +} + +ld get_t(pt v, line r) { // retorna t tal que t*v pertence a reta r + return (r.p^r.q) / ((r.p-r.q)^v); +} + +pt proj(pt p, line r) { // projecao do ponto p na reta r + if (r.p == r.q) return r.p; + r.q = r.q - r.p; p = p - r.p; + pt proj = r.q * ((p*r.q) / (r.q*r.q)); + return proj + r.p; +} + +pt inter(line r, line s) { // r inter s + if (eq((r.p - r.q) ^ (s.p - s.q), 0)) return pt(DINF, DINF); + r.q = r.q - r.p, s.p = s.p - r.p, s.q = s.q - r.p; + return r.q * get_t(r.q, s) + r.p; +} + +bool interseg(line r, line s) { // se o seg de r intersecta o seg de s + if (isinseg(r.p, s) or isinseg(r.q, s) + or isinseg(s.p, r) or isinseg(s.q, r)) return 1; + + return ccw(r.p, r.q, s.p) != ccw(r.p, r.q, s.q) and + ccw(s.p, s.q, r.p) != ccw(s.p, s.q, r.q); +} + +ld disttoline(pt p, line r) { // distancia do ponto a reta + return 2 * abs(sarea(p, r.p, r.q)) / dist(r.p, r.q); +} + +ld disttoseg(pt p, line r) { // distancia do ponto ao seg + if ((r.q - r.p)*(p - r.p) < 0) return dist(r.p, p); + if ((r.p - r.q)*(p - r.q) < 0) return dist(r.q, p); + return disttoline(p, r); +} + +ld distseg(line a, line b) { // distancia entre seg + if (interseg(a, b)) return 0; + + ld ret = DINF; + ret = min(ret, disttoseg(a.p, b)); + ret = min(ret, disttoseg(a.q, b)); + ret = min(ret, disttoseg(b.p, a)); + ret = min(ret, disttoseg(b.q, a)); + + return ret; +} + +// POLIGONO + +// corta poligono com a reta r deixando os pontos p tal que +// ccw(r.p, r.q, p) +vector cut_polygon(vector v, line r) { // O(n) + vector ret; + for (int j = 0; j < v.size(); j++) { + if (ccw(r.p, r.q, v[j])) ret.push_back(v[j]); + if (v.size() == 1) continue; + line s(v[j], v[(j+1)%v.size()]); + pt p = inter(r, s); + if (isinseg(p, s)) ret.push_back(p); + } + ret.erase(unique(ret.begin(), ret.end()), ret.end()); + if (ret.size() > 1 and ret.back() == ret[0]) ret.pop_back(); + return ret; +} + +// distancia entre os retangulos a e b (lados paralelos aos eixos) +// assume que ta representado (inferior esquerdo, superior direito) +ld dist_rect(pair a, pair b) { + ld hor = 0, vert = 0; + if (a.second.x < b.first.x) hor = b.first.x - a.second.x; + else if (b.second.x < a.first.x) hor = a.first.x - b.second.x; + if (a.second.y < b.first.y) vert = b.first.y - a.second.y; + else if (b.second.y < a.first.y) vert = a.first.y - b.second.y; + return dist(pt(0, 0), pt(hor, vert)); +} + +ld polarea(vector v) { // area do poligono + ld ret = 0; + for (int i = 0; i < v.size(); i++) + ret += sarea(pt(0, 0), v[i], v[(i + 1) % v.size()]); + return abs(ret); +} + +// se o ponto ta dentro do poligono: retorna 0 se ta fora, +// 1 se ta no interior e 2 se ta na borda +int inpol(vector& v, pt p) { // O(n) + int qt = 0; + for (int i = 0; i < v.size(); i++) { + if (p == v[i]) return 2; + int j = (i+1)%v.size(); + if (eq(p.y, v[i].y) and eq(p.y, v[j].y)) { + if ((v[i]-p)*(v[j]-p) < eps) return 2; + continue; + } + bool baixo = v[i].y+eps < p.y; + if (baixo == (v[j].y+eps < p.y)) continue; + auto t = (p-v[i])^(v[j]-v[i]); + if (eq(t, 0)) return 2; + if (baixo == (t > eps)) qt += baixo ? 1 : -1; + } + return qt != 0; +} + +bool interpol(vector v1, vector v2) { // se dois poligonos se intersectam - O(n*m) + int n = v1.size(), m = v2.size(); + for (int i = 0; i < n; i++) if (inpol(v2, v1[i])) return 1; + for (int i = 0; i < n; i++) if (inpol(v1, v2[i])) return 1; + for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) + if (interseg(line(v1[i], v1[(i+1)%n]), line(v2[j], v2[(j+1)%m]))) return 1; + return 0; +} + +ld distpol(vector v1, vector v2) { // distancia entre poligonos + if (interpol(v1, v2)) return 0; + + ld ret = DINF; + + for (int i = 0; i < v1.size(); i++) for (int j = 0; j < v2.size(); j++) + ret = min(ret, distseg(line(v1[i], v1[(i + 1) % v1.size()]), + line(v2[j], v2[(j + 1) % v2.size()]))); + return ret; +} + +vector convex_hull(vector v) { // convex hull - O(n log(n)) + sort(v.begin(), v.end()); + v.erase(unique(v.begin(), v.end()), v.end()); + if (v.size() <= 1) return v; + vector l, u; + for (int i = 0; i < v.size(); i++) { + while (l.size() > 1 and !ccw(l.end()[-2], l.end()[-1], v[i])) + l.pop_back(); + l.push_back(v[i]); + } + for (int i = v.size() - 1; i >= 0; i--) { + while (u.size() > 1 and !ccw(u.end()[-2], u.end()[-1], v[i])) + u.pop_back(); + u.push_back(v[i]); + } + l.pop_back(); u.pop_back(); + for (pt i : u) l.push_back(i); + return l; +} + +struct convex_pol { + vector pol; + + // nao pode ter ponto colinear no convex hull + convex_pol() {} + convex_pol(vector v) : pol(convex_hull(v)) {} + + // se o ponto ta dentro do hull - O(log(n)) + bool is_inside(pt p) { + if (pol.size() == 0) return false; + if (pol.size() == 1) return p == pol[0]; + int l = 1, r = pol.size(); + while (l < r) { + int m = (l+r)/2; + if (ccw(p, pol[0], pol[m])) l = m+1; + else r = m; + } + if (l == 1) return isinseg(p, line(pol[0], pol[1])); + if (l == pol.size()) return false; + return !ccw(p, pol[l], pol[l-1]); + } + // ponto extremo em relacao a cmp(p, q) = p mais extremo q + // (copiado de https://github.com/gustavoM32/caderno-zika) + int extreme(const function& cmp) { + int n = pol.size(); + auto extr = [&](int i, bool& cur_dir) { + cur_dir = cmp(pol[(i+1)%n], pol[i]); + return !cur_dir and !cmp(pol[(i+n-1)%n], pol[i]); + }; + bool last_dir, cur_dir; + if (extr(0, last_dir)) return 0; + int l = 0, r = n; + while (l+1 < r) { + int m = (l+r)/2; + if (extr(m, cur_dir)) return m; + bool rel_dir = cmp(pol[m], pol[l]); + if ((!last_dir and cur_dir) or + (last_dir == cur_dir and rel_dir == cur_dir)) { + l = m; + last_dir = cur_dir; + } else r = m; + } + return l; + } + int max_dot(pt v) { + return extreme([&](pt p, pt q) { return p*v > q*v; }); + } + pair tangents(pt p) { + auto L = [&](pt q, pt r) { return ccw(p, r, q); }; + auto R = [&](pt q, pt r) { return ccw(p, q, r); }; + return {extreme(L), extreme(R)}; + } +}; + +// CIRCUNFERENCIA + +pt getcenter(pt a, pt b, pt c) { // centro da circunf dado 3 pontos + b = (a + b) / 2; + c = (a + c) / 2; + return inter(line(b, b + rotate90(a - b)), + line(c, c + rotate90(a - c))); +} + +vector circ_line_inter(pt a, pt b, pt c, ld r) { // intersecao da circunf (c, r) e reta ab + vector ret; + b = b-a, a = a-c; + ld A = b*b; + ld B = a*b; + ld C = a*a - r*r; + ld D = B*B - A*C; + if (D < -eps) return ret; + ret.push_back(c+a+b*(-B+sqrt(D+eps))/A); + if (D > eps) ret.push_back(c+a+b*(-B-sqrt(D))/A); + return ret; +} + +vector circ_inter(pt a, pt b, ld r, ld R) { // intersecao da circunf (a, r) e (b, R) + vector ret; + ld d = dist(a, b); + if (d > r+R or d+min(r, R) < max(r, R)) return ret; + ld x = (d*d-R*R+r*r)/(2*d); + ld y = sqrt(r*r-x*x); + pt v = (b-a)/d; + ret.push_back(a+v*x + rotate90(v)*y); + if (y > 0) ret.push_back(a+v*x - rotate90(v)*y); + return ret; +} + +bool operator <(const line& a, const line& b) { // comparador pra reta + // assume que as retas tem p < q + pt v1 = a.q - a.p, v2 = b.q - b.p; + if (!eq(angle(v1), angle(v2))) return angle(v1) < angle(v2); + return ccw(a.p, a.q, b.p); // mesmo angulo +} +bool operator ==(const line& a, const line& b) { + return !(a < b) and !(b < a); +} + +// comparador pro set pra fazer sweep line com segmentos +struct cmp_sweepline { + bool operator () (const line& a, const line& b) const { + // assume que os segmentos tem p < q + if (a.p == b.p) return ccw(a.p, a.q, b.q); + if (!eq(a.p.x, a.q.x) and (eq(b.p.x, b.q.x) or a.p.x+eps < b.p.x)) + return ccw(a.p, a.q, b.p); + return ccw(a.p, b.q, b.p); + } +}; + +// comparador pro set pra fazer sweep angle com segmentos +pt dir; +struct cmp_sweepangle { + bool operator () (const line& a, const line& b) const { + return get_t(dir, a) + eps < get_t(dir, b); + } +}; +``` diff --git a/content/docs/Primitivas/geometria3d.md b/content/docs/Primitivas/geometria3d.md new file mode 100644 index 0000000..1f2cfd4 --- /dev/null +++ b/content/docs/Primitivas/geometria3d.md @@ -0,0 +1,188 @@ +--- +weight: 10 +title: "Geometria 3D" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre +Link original: [geometria3d.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Primitivas/geometria3d.cpp) + +## Código +```cpp +typedef double ld; +const ld DINF = 1e18; +const ld eps = 1e-9; + +#define sq(x) ((x)*(x)) + +bool eq(ld a, ld b) { + return abs(a - b) <= eps; +} + +struct pt { // ponto + ld x, y, z; + pt(ld x_ = 0, ld y_ = 0, ld z_ = 0) : x(x_), y(y_), z(z_) {} + bool operator < (const pt p) const { + if (!eq(x, p.x)) return x < p.x; + if (!eq(y, p.y)) return y < p.y; + if (!eq(z, p.z)) return z < p.z; + return 0; + } + bool operator == (const pt p) const { + return eq(x, p.x) and eq(y, p.y) and eq(z, p.z); + } + pt operator + (const pt p) const { return pt(x+p.x, y+p.y, z+p.z); } + pt operator - (const pt p) const { return pt(x-p.x, y-p.y, z-p.z); } + pt operator * (const ld c) const { return pt(x*c , y*c , z*c ); } + pt operator / (const ld c) const { return pt(x/c , y/c , z/c ); } + ld operator * (const pt p) const { return x*p.x + y*p.y + z*p.z; } + pt operator ^ (const pt p) const { return pt(y*p.z - z*p.y, z*p.x - x*p.z, x*p.y - y*p.x); } + friend istream& operator >> (istream& in, pt& p) { + return in >> p.x >> p.y >> p.z; + } +}; + +struct line { // reta + pt p, q; + line() {} + line(pt p_, pt q_) : p(p_), q(q_) {} + friend istream& operator >> (istream& in, line& r) { + return in >> r.p >> r.q; + } +}; + +struct plane { // plano + array p; // pontos que definem o plano + array eq; // equacao do plano + plane() {} + plane(pt p_, pt q_, pt r_) : p({p_, q_, r_}) { build(); } + + friend istream& operator >> (istream& in, plane& P) { + return in >> P.p[0] >> P.p[1] >> P.p[2]; + P.build(); + } + void build() { + pt dir = (p[1] - p[0]) ^ (p[2] - p[0]); + eq = {dir.x, dir.y, dir.z, dir*p[0]*(-1)}; + } +}; + +// converte de coordenadas polares para cartesianas +// (angulos devem estar em radianos) +// phi eh o angulo com o eixo z (cima) theta eh o angulo de rotacao ao redor de z +pt convert(ld rho, ld th, ld phi) { + return pt(sin(phi) * cos(th), sin(phi) * sin(th), cos(phi)) * rho; +} + +// projecao do ponto p na reta r +pt proj(pt p, line r) { + if (r.p == r.q) return r.p; + r.q = r.q - r.p; p = p - r.p; + pt proj = r.q * ((p*r.q) / (r.q*r.q)); + return proj + r.p; +} + +// projecao do ponto p no plano P +pt proj(pt p, plane P) { + p = p - P.p[0], P.p[1] = P.p[1] - P.p[0], P.p[2] = P.p[2] - P.p[0]; + pt norm = P.p[1] ^ P.p[2]; + pt proj = p - (norm * (norm * p) / (norm*norm)); + return proj + P.p[0]; +} + +// distancia +ld dist(pt a, pt b) { + return sqrt(sq(a.x-b.x) + sq(a.y-b.y) + sq(a.z-b.z)); +} + +// distancia ponto reta +ld distline(pt p, line r) { + return dist(p, proj(p, r)); +} + +// distancia de ponto para segmento +ld distseg(pt p, line r) { + if ((r.q - r.p)*(p - r.p) < 0) return dist(r.p, p); + if ((r.p - r.q)*(p - r.q) < 0) return dist(r.q, p); + return distline(p, r); +} + +// distancia de ponto a plano com sinal +ld sdist(pt p, plane P) { + return P.eq[0]*p.x + P.eq[1]*p.y + P.eq[2]*p.z + P.eq[3]; +} + +// distancia de ponto a plano +ld distplane(pt p, plane P) { + return abs(sdist(p, P)); +} + +// se ponto pertence a reta +bool isinseg(pt p, line r) { + return eq(distseg(p, r), 0); +} + +// se ponto pertence ao triangulo definido por P.p +bool isinpol(pt p, vector v) { + assert(v.size() >= 3); + pt norm = (v[1]-v[0]) ^ (v[2]-v[1]); + bool inside = true; + int sign = -1; + for (int i = 0; i < v.size(); i++) { + line r(v[(i+1)%3], v[i]); + if (isinseg(p, r)) return true; + + pt ar = v[(i+1)%3] - v[i]; + if (sign == -1) sign = ((ar^(p-v[i]))*norm > 0); + else if (((ar^(p-v[i]))*norm > 0) != sign) inside = false; + } + return inside; +} + +// distancia de ponto ate poligono +ld distpol(pt p, vector v) { + pt p2 = proj(p, plane(v[0], v[1], v[2])); + if (isinpol(p2, v)) return dist(p, p2); + ld ret = DINF; + for (int i = 0; i < v.size(); i++) { + int j = (i+1)%v.size(); + ret = min(ret, distseg(p, line(v[i], v[j]))); + } + return ret; +} + +// intersecao de plano e segmento +// BOTH = o segmento esta no plano +// ONE = um dos pontos do segmento esta no plano +// PARAL = segmento paralelo ao plano +// CONCOR = segmento concorrente ao plano +enum RETCODE {BOTH, ONE, PARAL, CONCOR}; +pair intersect(plane P, line r) { + ld d1 = sdist(r.p, P); + ld d2 = sdist(r.q, P); + if (eq(d1, 0) and eq(d2, 0)) + return pair(BOTH, r.p); + if (eq(d1, 0)) + return pair(ONE, r.p); + if (eq(d2, 0)) + return pair(ONE, r.q); + if ((d1 > 0 and d2 > 0) or (d1 < 0 and d2 < 0)) { + if (eq(d1-d2, 0)) return pair(PARAL, pt()); + return pair(CONCOR, pt()); + } + ld frac = d1 / (d1 - d2); + pt res = r.p + ((r.q - r.p) * frac); + return pair(ONE, res); +} + +// rotaciona p ao redor do eixo u por um angulo a +pt rotate(pt p, pt u, ld a) { + u = u / dist(u, pt()); + return u * (u * p) + (u ^ p ^ u) * cos(a) + (u ^ p) * sin(a); +} + +``` diff --git a/content/docs/Primitivas/geometriaInt.md b/content/docs/Primitivas/geometriaInt.md new file mode 100644 index 0000000..9a9cdcd --- /dev/null +++ b/content/docs/Primitivas/geometriaInt.md @@ -0,0 +1,251 @@ +--- +weight: 10 +title: "Geometria - inteiro" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre +Link original: [geometriaInt.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Primitivas/geometriaInt.cpp) + +## Código +```cpp +#define sq(x) ((x)*(ll)(x)) + +struct pt { // ponto + int x, y; + pt(int x_ = 0, int y_ = 0) : x(x_), y(y_) {} + bool operator < (const pt p) const { + if (x != p.x) return x < p.x; + return y < p.y; + } + bool operator == (const pt p) const { + return x == p.x and y == p.y; + } + pt operator + (const pt p) const { return pt(x+p.x, y+p.y); } + pt operator - (const pt p) const { return pt(x-p.x, y-p.y); } + pt operator * (const int c) const { return pt(x*c, y*c); } + ll operator * (const pt p) const { return x*(ll)p.x + y*(ll)p.y; } + ll operator ^ (const pt p) const { return x*(ll)p.y - y*(ll)p.x; } + friend istream& operator >> (istream& in, pt& p) { + return in >> p.x >> p.y; + } +}; + +struct line { // reta + pt p, q; + line() {} + line(pt p_, pt q_) : p(p_), q(q_) {} + friend istream& operator >> (istream& in, line& r) { + return in >> r.p >> r.q; + } +}; + +// PONTO & VETOR + +ll dist2(pt p, pt q) { // quadrado da distancia + return sq(p.x - q.x) + sq(p.y - q.y); +} + +ll sarea2(pt p, pt q, pt r) { // 2 * area com sinal + return (q-p)^(r-q); +} + +bool col(pt p, pt q, pt r) { // se p, q e r sao colin. + return sarea2(p, q, r) == 0; +} + +bool ccw(pt p, pt q, pt r) { // se p, q, r sao ccw + return sarea2(p, q, r) > 0; +} + +int quad(pt p) { // quadrante de um ponto + return (p.x<0)^3*(p.y<0); +} + +bool compare_angle(pt p, pt q) { // retorna se ang(p) < ang(q) + if (quad(p) != quad(q)) return quad(p) < quad(q); + return ccw(q, pt(0, 0), p); +} + +pt rotate90(pt p) { // rotaciona 90 graus + return pt(-p.y, p.x); +} + +// RETA + +bool isinseg(pt p, line r) { // se p pertence ao seg de r + pt a = r.p - p, b = r.q - p; + return (a ^ b) == 0 and (a * b) <= 0; +} + +bool interseg(line r, line s) { // se o seg de r intersecta o seg de s + if (isinseg(r.p, s) or isinseg(r.q, s) + or isinseg(s.p, r) or isinseg(s.q, r)) return 1; + + return ccw(r.p, r.q, s.p) != ccw(r.p, r.q, s.q) and + ccw(s.p, s.q, r.p) != ccw(s.p, s.q, r.q); +} + +int segpoints(line r) { // numero de pontos inteiros no segmento + return 1 + __gcd(abs(r.p.x - r.q.x), abs(r.p.y - r.q.y)); +} + +double get_t(pt v, line r) { // retorna t tal que t*v pertence a reta r + return (r.p^r.q) / (double) ((r.p-r.q)^v); +} + +// POLIGONO + +// quadrado da distancia entre os retangulos a e b (lados paralelos aos eixos) +// assume que ta representado (inferior esquerdo, superior direito) +ll dist2_rect(pair a, pair b) { + int hor = 0, vert = 0; + if (a.second.x < b.first.x) hor = b.first.x - a.second.x; + else if (b.second.x < a.first.x) hor = a.first.x - b.second.x; + if (a.second.y < b.first.y) vert = b.first.y - a.second.y; + else if (b.second.y < a.first.y) vert = a.first.y - b.second.y; + return sq(hor) + sq(vert); +} + +ll polarea2(vector v) { // 2 * area do poligono + ll ret = 0; + for (int i = 0; i < v.size(); i++) + ret += sarea2(pt(0, 0), v[i], v[(i + 1) % v.size()]); + return abs(ret); +} + +// se o ponto ta dentro do poligono: retorna 0 se ta fora, +// 1 se ta no interior e 2 se ta na borda +int inpol(vector& v, pt p) { // O(n) + int qt = 0; + for (int i = 0; i < v.size(); i++) { + if (p == v[i]) return 2; + int j = (i+1)%v.size(); + if (p.y == v[i].y and p.y == v[j].y) { + if ((v[i]-p)*(v[j]-p) <= 0) return 2; + continue; + } + bool baixo = v[i].y < p.y; + if (baixo == (v[j].y < p.y)) continue; + auto t = (p-v[i])^(v[j]-v[i]); + if (!t) return 2; + if (baixo == (t > 0)) qt += baixo ? 1 : -1; + } + return qt != 0; +} + +vector convex_hull(vector v) { // convex hull - O(n log(n)) + sort(v.begin(), v.end()); + v.erase(unique(v.begin(), v.end()), v.end()); + if (v.size() <= 1) return v; + vector l, u; + for (int i = 0; i < v.size(); i++) { + while (l.size() > 1 and !ccw(l.end()[-2], l.end()[-1], v[i])) + l.pop_back(); + l.push_back(v[i]); + } + for (int i = v.size() - 1; i >= 0; i--) { + while (u.size() > 1 and !ccw(u.end()[-2], u.end()[-1], v[i])) + u.pop_back(); + u.push_back(v[i]); + } + l.pop_back(); u.pop_back(); + for (pt i : u) l.push_back(i); + return l; +} + +ll interior_points(vector v) { // pontos inteiros dentro de um poligono simples + ll b = 0; + for (int i = 0; i < v.size(); i++) + b += segpoints(line(v[i], v[(i+1)%v.size()])) - 1; + return (polarea2(v) - b) / 2 + 1; +} + +struct convex_pol { + vector pol; + + // nao pode ter ponto colinear no convex hull + convex_pol() {} + convex_pol(vector v) : pol(convex_hull(v)) {} + + // se o ponto ta dentro do hull - O(log(n)) + bool is_inside(pt p) { + if (pol.size() == 0) return false; + if (pol.size() == 1) return p == pol[0]; + int l = 1, r = pol.size(); + while (l < r) { + int m = (l+r)/2; + if (ccw(p, pol[0], pol[m])) l = m+1; + else r = m; + } + if (l == 1) return isinseg(p, line(pol[0], pol[1])); + if (l == pol.size()) return false; + return !ccw(p, pol[l], pol[l-1]); + } + // ponto extremo em relacao a cmp(p, q) = p mais extremo q + // (copiado de https://github.com/gustavoM32/caderno-zika) + int extreme(const function& cmp) { + int n = pol.size(); + auto extr = [&](int i, bool& cur_dir) { + cur_dir = cmp(pol[(i+1)%n], pol[i]); + return !cur_dir and !cmp(pol[(i+n-1)%n], pol[i]); + }; + bool last_dir, cur_dir; + if (extr(0, last_dir)) return 0; + int l = 0, r = n; + while (l+1 < r) { + int m = (l+r)/2; + if (extr(m, cur_dir)) return m; + bool rel_dir = cmp(pol[m], pol[l]); + if ((!last_dir and cur_dir) or + (last_dir == cur_dir and rel_dir == cur_dir)) { + l = m; + last_dir = cur_dir; + } else r = m; + } + return l; + } + int max_dot(pt v) { + return extreme([&](pt p, pt q) { return p*v > q*v; }); + } + pair tangents(pt p) { + auto L = [&](pt q, pt r) { return ccw(p, r, q); }; + auto R = [&](pt q, pt r) { return ccw(p, q, r); }; + return {extreme(L), extreme(R)}; + } +}; + +bool operator <(const line& a, const line& b) { // comparador pra reta + // assume que as retas tem p < q + pt v1 = a.q - a.p, v2 = b.q - b.p; + bool b1 = compare_angle(v1, v2), b2 = compare_angle(v2, v1); + if (b1 or b2) return b1; + return ccw(a.p, a.q, b.p); // mesmo angulo +} +bool operator ==(const line& a, const line& b) { + return !(a < b) and !(b < a); +} + +// comparador pro set pra fazer sweep line com segmentos +struct cmp_sweepline { + bool operator () (const line& a, const line& b) const { + // assume que os segmentos tem p < q + if (a.p == b.p) return ccw(a.p, a.q, b.q); + if (a.p.x != a.q.x and (b.p.x == b.q.x or a.p.x < b.p.x)) + return ccw(a.p, a.q, b.p); + return ccw(a.p, b.q, b.p); + } +}; + +// comparador pro set pra fazer sweep angle com segmentos +pt dir; +struct cmp_sweepangle { + bool operator () (const line& a, const line& b) const { + return get_t(dir, a) < get_t(dir, b); + } +}; +``` diff --git a/content/docs/Primitivas/matrix.md b/content/docs/Primitivas/matrix.md new file mode 100644 index 0000000..7746fa7 --- /dev/null +++ b/content/docs/Primitivas/matrix.md @@ -0,0 +1,76 @@ +--- +weight: 10 +title: "Matriz" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre +Link original: [matrix.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Primitivas/matrix.cpp) + +## Código +```cpp +#define MODULAR false +template struct matrix : vector> { + int n, m; + + void print() { + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) cout << (*this)[i][j] << " "; + cout << endl; + } + } + + matrix(int n_, int m_, bool ident = false) : + vector>(n_, vector(m_, 0)), n(n_), m(m_) { + if (ident) { + assert(n == m); + for (int i = 0; i < n; i++) (*this)[i][i] = 1; + } + } + matrix(const vector>& c) : vector>(c), + n(c.size()), m(c[0].size()) {} + matrix(const initializer_list>& c) { + vector> val; + for (auto& i : c) val.push_back(i); + *this = matrix(val); + } + + matrix operator*(matrix& r) { + assert(m == r.n); + matrix M(n, r.m); + for (int i = 0; i < n; i++) for (int k = 0; k < m; k++) + for (int j = 0; j < r.m; j++) { + T add = (*this)[i][k] * r[k][j]; +#if MODULAR +#warning Usar matrix e soh colocar valores em [0, MOD) na matriz! + M[i][j] += add%MOD; + if (M[i][j] >= MOD) M[i][j] -= MOD; +#else + M[i][j] += add; +#endif + } + return M; + } + matrix operator^(ll e){ + matrix M(n, n, true), at = *this; + while (e) { + if (e&1) M = M*at; + e >>= 1; + at = at*at; + } + return M; + } + void apply_transform(matrix M, ll e){ + auto& v = *this; + while (e) { + if (e&1) v = M*v; + e >>= 1; + M = M*M; + } + } +}; +``` diff --git a/content/docs/Primitivas/matroid.md b/content/docs/Primitivas/matroid.md new file mode 100644 index 0000000..91e58e0 --- /dev/null +++ b/content/docs/Primitivas/matroid.md @@ -0,0 +1,218 @@ +--- +weight: 10 +title: "Matroid" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Matroids de Grafo e Particao + + De modo geral, toda Matroid contem um build() linear + + e uma funcao constante oracle() + + oracle(i) responde se o conjunto continua independente + + apos adicao do elemento i + + oracle(i, j) responde se o conjunto continua indepente + + apos trocar o elemento i pelo elemento j + + + + Intersecao sem peso O(r^2 n) + + em que n eh o tamanho do conjunto e r eh o tamanho da resposta + + + + Matroid Grafica + + Matroid das florestas de um grafo + + Um conjunto de arestas eh independente se formam uma floresta + + + + build() : O(n) + + oracle() : O(1) + + + +Link original: [matroid.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Primitivas/matroid.cpp) + +## Código +```cpp +struct graphic_matroid { + int n, m, t; + vector> edges; + vector> g; + vector comp, in, out; + graphic_matroid(int n_, vector> edges_) + : n(n_), m(edges_.size()), edges(edges_), g(n), comp(n), in(n), out(n) {} + void dfs(int u) { + in[u] = t++; + for (auto v : g[u]) if (in[v] == -1) + comp[v] = comp[u], dfs(v); + out[u] = t; + } + void build(vector I) { + t = 0; + for (int u = 0; u < n; u++) g[u].clear(), in[u] = -1; + for (int e : I) { + auto [u, v] = edges[e]; + g[u].push_back(v), g[v].push_back(u); + } + for (int u = 0; u < n; u++) if (in[u] == -1) + comp[u] = u, dfs(u); + } + bool is_ancestor(int u, int v) { + return in[u] <= in[v] and in[v] < out[u]; + } + bool oracle(int e) { + return comp[edges[e][0]] != comp[edges[e][1]]; + } + bool oracle(int e, int f) { + if (oracle(f)) return true; + int u = edges[e][in[edges[e][0]] < in[edges[e][1]]]; + return is_ancestor(u, edges[f][0]) != is_ancestor(u, edges[f][1]); + } +}; + +// Matroid de particao ou cores +// Um conjunto eh independente se a quantidade de elementos +// de cada cor nao excede a capacidade da cor +// Quando todas as capacidades sao 1, um conjunto eh independente +// se todas as suas cores sao distintas +// +// build() : O(n) +// oracle() : O(1) + +struct partition_matroid { + vector cap, color, d; + partition_matroid(vector cap_, vector color_) + : cap(cap_), color(color_), d(cap.size()) {} + void build(vector I) { + fill(d.begin(), d.end(), 0); + for (int u : I) d[color[u]]++; + } + bool oracle(int u) { + return d[color[u]] < cap[color[u]]; + } + bool oracle(int u, int v) { + return color[u] == color[v] or oracle(v); + } +}; + +// Intersecao de matroid sem pesos +// Dadas duas matroids M1 e M2 definidas sobre o mesmo +// conjunto I, retorna o maior subconjunto de I +// que eh independente tanto para M1 quanto para M2 +// +// O(r^2*n) + +// Matroid "pesada" deve ser a M2 +template +vector matroid_intersection(int n, Matroid1 M1, Matroid2 M2) { + vector b(n); + vector I[2]; + bool converged = false; + while (!converged) { + I[0].clear(), I[1].clear(); + for (int u = 0; u < n; u++) I[b[u]].push_back(u); + + M1.build(I[1]), M2.build(I[1]); + vector target(n), pushed(n); + queue q; + for (int u : I[0]) { + target[u] = M2.oracle(u); + if (M1.oracle(u)) pushed[u] = true, q.push(u); + } + vector p(n, -1); + converged = true; + while (q.size()) { + int u = q.front(); q.pop(); + if (target[u]) { + converged = false; + for (int v = u; v != -1; v = p[v]) b[v] = !b[v]; + break; + } + for (int v : I[!b[u]]) if (!pushed[v]) { + if ((b[u] and M1.oracle(u, v)) or (b[v] and M2.oracle(v, u))) + p[v] = u, pushed[v] = true, q.push(v); + } + } + } + return I[1]; +} + +// Intersecao de matroid com pesos +// Dadas duas matroids M1 e M2 e uma funcao de pesos w, todas definidas sobre +// um conjunto I retorna o maior subconjunto de I (desempatado pelo menor peso) +// que eh independente tanto para M1 quanto para M2 +// A resposta eh construida incrementando o tamanho conjunto I de 1 em 1 +// Se nao tiver custo negativo, nao precisa de SPFA +// +// O(r^3*n) com SPFA +// O(r^2*n*log(n)) com Dijkstra e potencial + +template +vector weighted_matroid_intersection(int n, vector w, Matroid1 M1, Matroid2 M2) { + vector b(n), target(n), is_inside(n); + vector I[2], from(n); + vector> d(n); + auto check_edge = [&](int u, int v) { + return (b[u] and M1.oracle(u, v)) or (b[v] and M2.oracle(v, u)); + }; + while (true) { + I[0].clear(), I[1].clear(); + for (int u = 0; u < n; u++) I[b[u]].push_back(u); + // I[1] contem o conjunto de tamanho I[1].size() de menor peso + M1.build(I[1]), M2.build(I[1]); + for (int u = 0; u < n; u++) { + target[u] = false, is_inside[u] = false, from[u] = -1; + d[u] = {numeric_limits::max(), INF}; + } + deque q; + sort(I[0].begin(), I[0].end(), [&](int i, int j){ return w[i] < w[j]; }); + for (int u : I[0]) { + target[u] = M2.oracle(u); + if (M1.oracle(u)) { + if (is_inside[u]) continue; + d[u] = {w[u], 0}; + if (!q.empty() and d[u] > d[q.front()]) q.push_back(u); + else q.push_front(u); + is_inside[u] = true; + } + } + while (q.size()) { + int u = q.front(); q.pop_front(); + is_inside[u] = false; + for (int v : I[!b[u]]) if (check_edge(u, v)) { + pair nd(d[u].first + w[v], d[u].second + 1); + if (nd < d[v]) { + from[v] = u, d[v] = nd; + if (is_inside[v]) continue; + if (q.size() and d[v] > d[q.front()]) q.push_back(v); + else q.push_front(v); + is_inside[v] = true; + } + } + } + pair mini = pair(numeric_limits::max(), INF); + int targ = -1; + for (int u : I[0]) if (target[u] and d[u] < mini) + mini = d[u], targ = u; + if (targ != -1) for (int u = targ; u != -1; u = from[u]) + b[u] = !b[u], w[u] *= -1; + else break; + } + return I[1]; +} +``` diff --git a/content/docs/Primitivas/modularArithmetic.md b/content/docs/Primitivas/modularArithmetic.md new file mode 100644 index 0000000..36403a7 --- /dev/null +++ b/content/docs/Primitivas/modularArithmetic.md @@ -0,0 +1,88 @@ +--- +weight: 10 +title: "Aritmetica Modular" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + O mod tem q ser primo + + + +Link original: [modularArithmetic.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Primitivas/modularArithmetic.cpp) + +## Código +```cpp +template struct mod_int { + ll expo(ll b, ll e) { + ll ret = 1; + while (e) { + if (e % 2) ret = ret * b % p; + e /= 2, b = b * b % p; + } + return ret; + } + ll inv(ll b) { return expo(b, p-2); } + + using m = mod_int; + int v; + mod_int() : v(0) {} + mod_int(ll v_) { + if (v_ >= p or v_ <= -p) v_ %= p; + if (v_ < 0) v_ += p; + v = v_; + } + m& operator +=(const m& a) { + v += a.v; + if (v >= p) v -= p; + return *this; + } + m& operator -=(const m& a) { + v -= a.v; + if (v < 0) v += p; + return *this; + } + m& operator *=(const m& a) { + v = v * ll(a.v) % p; + return *this; + } + m& operator /=(const m& a) { + v = v * inv(a.v) % p; + return *this; + } + m operator -(){ return m(-v); } + m& operator ^=(ll e) { + if (e < 0) { + v = inv(v); + e = -e; + } + v = expo(v, e); + // possivel otimizacao: + // cuidado com 0^0 + // v = expo(v, e%(p-1)); + return *this; + } + bool operator ==(const m& a) { return v == a.v; } + bool operator !=(const m& a) { return v != a.v; } + + friend istream& operator >>(istream& in, m& a) { + ll val; in >> val; + a = m(val); + return in; + } + friend ostream& operator <<(ostream& out, m a) { + return out << a.v; + } + friend m operator +(m a, m b) { return a += b; } + friend m operator -(m a, m b) { return a -= b; } + friend m operator *(m a, m b) { return a *= b; } + friend m operator /(m a, m b) { return a /= b; } + friend m operator ^(m a, ll e) { return a ^= e; } +}; + +typedef mod_int<(int)1e9+7> mint; +``` diff --git a/content/docs/Problemas/_index.md b/content/docs/Problemas/_index.md new file mode 100644 index 0000000..981b5b3 --- /dev/null +++ b/content/docs/Problemas/_index.md @@ -0,0 +1,8 @@ +--- +weight: 10 +title: "Problemas" +draft: false +date: "2024-05-09T17:19:25-0300" +description: "" +publishdate: "2024-05-09T17:19:25-0300" +--- diff --git a/content/docs/Problemas/additionChain.md b/content/docs/Problemas/additionChain.md new file mode 100644 index 0000000..0ab4e0e --- /dev/null +++ b/content/docs/Problemas/additionChain.md @@ -0,0 +1,49 @@ +--- +weight: 10 +title: "Shortest Addition Chain" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Computa o menor numero de adicoes para construir + + cada valor, comecando com 1 (e podendo salvar variaveis) + + Retorna um par com a dp e o pai na arvore + + A arvore eh tao que o taminho da raiz (1) ate x + + contem os valores que devem ser criados para gerar x + + A profundidade de x na arvore eh dp[x] + + DP funciona para ateh 300, mas a arvore soh funciona + + para ateh 148 + + + + recuperacao certa soh ateh 148 (erra para 149, 233, 298) + +Link original: [additionChain.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/additionChain.cpp) + +## Código +```cpp +pair, vector> addition_chain() { + int MAX = 301; + vector dp(MAX), p(MAX); + for (int n = 2; n < MAX; n++) { + pair val = {INF, -1}; + for (int i = 1; i < n; i++) for (int j = i; j; j = p[j]) + if (j == n-i) val = min(val, pair(dp[i]+1, i)); + tie(dp[n], p[n]) = val; + if (n == 9) p[n] = 8; + if (n == 149 or n == 233) dp[n]--; + } + return {dp, p}; +} +``` diff --git a/content/docs/Problemas/angleRange.md b/content/docs/Problemas/angleRange.md new file mode 100644 index 0000000..930435e --- /dev/null +++ b/content/docs/Problemas/angleRange.md @@ -0,0 +1,61 @@ +--- +weight: 10 +title: "Angle Range Intersection" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Computa intersecao de angulos + + Os angulos (arcos) precisam ter comprimeiro < pi + + (caso contrario a intersecao eh estranha) + + + + Tudo O(1) + + + +Link original: [angleRange.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/angleRange.cpp) + +## Código +```cpp +struct angle_range { + static constexpr ld ALL = 1e9, NIL = -1e9; + ld l, r; + angle_range() : l(ALL), r(ALL) {} + angle_range(ld l_, ld r_) : l(l_), r(r_) { fix(l), fix(r); } + + void fix(ld& theta) { + if (theta == ALL or theta == NIL) return; + if (theta > 2*pi) theta -= 2*pi; + if (theta < 0) theta += 2*pi; + } + bool empty() { return l == NIL; } + bool contains(ld q) { + fix(q); + if (l == ALL) return true; + if (l == NIL) return false; + if (l < r) return l < q and q < r; + return q > l or q < r; + } + friend angle_range operator &(angle_range p, angle_range q) { + if (p.l == ALL or q.l == NIL) return q; + if (q.l == ALL or p.l == NIL) return p; + if (p.l > p.r and q.l > q.r) return {max(p.l, q.l) , min(p.r, q.r)}; + if (q.l > q.r) swap(p.l, q.l), swap(p.r, q.r); + if (p.l > p.r) { + if (q.r > p.l) return {max(q.l, p.l) , q.r}; + else if (q.l < p.r) return {q.l, min(q.r, p.r)}; + return {NIL, NIL}; + } + if (max(p.l, q.l) > min(p.r, q.r)) return {NIL, NIL}; + return {max(p.l, q.l), min(p.r, q.r)}; + } +}; +``` diff --git a/content/docs/Problemas/areaHistograma.md b/content/docs/Problemas/areaHistograma.md new file mode 100644 index 0000000..feab6f5 --- /dev/null +++ b/content/docs/Problemas/areaHistograma.md @@ -0,0 +1,44 @@ +--- +weight: 10 +title: "Area Maxima de Histograma" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Assume que todas as barras tem largura 1, + + e altura dada no vetor v + + + + O(n) + + + +Link original: [areaHistograma.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/areaHistograma.cpp) + +## Código +```cpp +ll area(vector v) { + ll ret = 0; + stack s; + // valores iniciais pra dar tudo certo + v.insert(v.begin(), -1); + v.insert(v.end(), -1); + s.push(0); + + for(int i = 0; i < (int) v.size(); i++) { + while (v[s.top()] > v[i]) { + ll h = v[s.top()]; s.pop(); + ret = max(ret, h * (i - s.top() - 1)); + } + s.push(i); + } + + return ret; +} +``` diff --git a/content/docs/Problemas/areaUniaoRetangulo.md b/content/docs/Problemas/areaUniaoRetangulo.md new file mode 100644 index 0000000..03e0a1a --- /dev/null +++ b/content/docs/Problemas/areaUniaoRetangulo.md @@ -0,0 +1,106 @@ +--- +weight: 10 +title: "Area da Uniao de Retangulos" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + O(n log(n)) + + 5d8d2f + + + +Link original: [areaUniaoRetangulo.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/areaUniaoRetangulo.cpp) + +## Código +```cpp +namespace seg { + pair seg[4*MAX]; + ll lazy[4*MAX], *v; + int n; + + pair merge(pair l, pair r){ + if (l.second == r.second) return {l.first+r.first, l.second}; + else if (l.second < r.second) return l; + else return r; + } + + pair build(int p=1, int l=0, int r=n-1) { + lazy[p] = 0; + if (l == r) return seg[p] = {1, v[l]}; + int m = (l+r)/2; + return seg[p] = merge(build(2*p, l, m), build(2*p+1, m+1, r)); + } + void build(int n2, ll* v2) { + n = n2, v = v2; + build(); + } + void prop(int p, int l, int r) { + seg[p].second += lazy[p]; + if (l != r) lazy[2*p] += lazy[p], lazy[2*p+1] += lazy[p]; + lazy[p] = 0; + } + pair query(int a, int b, int p=1, int l=0, int r=n-1) { + prop(p, l, r); + if (a <= l and r <= b) return seg[p]; + if (b < l or r < a) return {0, LINF}; + int m = (l+r)/2; + return merge(query(a, b, 2*p, l, m), query(a, b, 2*p+1, m+1, r)); + } + pair update(int a, int b, int x, int p=1, int l=0, int r=n-1) { + prop(p, l, r); + if (a <= l and r <= b) { + lazy[p] += x; + prop(p, l, r); + return seg[p]; + } + if (b < l or r < a) return seg[p]; + int m = (l+r)/2; + return seg[p] = merge(update(a, b, x, 2*p, l, m), + update(a, b, x, 2*p+1, m+1, r)); + } +}; + +ll seg_vec[MAX]; + +ll area_sq(vector, pair>> &sq){ + vector, pair>> up; + for (auto it : sq){ + int x1, y1, x2, y2; + tie(x1, y1) = it.first; + tie(x2, y2) = it.second; + up.push_back({{x1+1, 1}, {y1, y2}}); + up.push_back({{x2+1, -1}, {y1, y2}}); + } + sort(up.begin(), up.end()); + memset(seg_vec, 0, sizeof seg_vec); + ll H_MAX = MAX; + seg::build(H_MAX-1, seg_vec); + auto it = up.begin(); + ll ans = 0; + while (it != up.end()){ + ll L = (*it).first.first; + while (it != up.end() && (*it).first.first == L){ + int x, inc, y1, y2; + tie(x, inc) = it->first; + tie(y1, y2) = it->second; + seg::update(y1+1, y2, inc); + it++; + } + if (it == up.end()) break; + ll R = (*it).first.first; + + ll W = R-L; + auto jt = seg::query(0, H_MAX-1); + ll H = H_MAX - 1; + if (jt.second == 0) H -= jt.first; + ans += W*H; + } + return ans; +} +``` diff --git a/content/docs/Problemas/binomial.md b/content/docs/Problemas/binomial.md new file mode 100644 index 0000000..1970439 --- /dev/null +++ b/content/docs/Problemas/binomial.md @@ -0,0 +1,100 @@ +--- +weight: 10 +title: "Binomial modular" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Computa C(n, k) mod m em O(m + log(m) log(n)) + + = O(rapido) + + + +Link original: [binomial.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/binomial.cpp) + +## Código +```cpp +ll divi[MAX]; + +ll expo(ll a, ll b, ll m) { + if (!b) return 1; + ll ans = expo(a*a%m, b/2, m); + if (b%2) ans *= a; + return ans%m; +} + +ll inv(ll a, ll b){ + return 1 tuple ext_gcd(T a, T b) { + if (!a) return {b, 0, 1}; + auto [g, x, y] = ext_gcd(b%a, a); + return {g, y - b/a*x, x}; +} + +template struct crt { + T a, m; + + crt() : a(0), m(1) {} + crt(T a_, T m_) : a(a_), m(m_) {} + crt operator * (crt C) { + auto [g, x, y] = ext_gcd(m, C.m); + if ((a - C.a) % g) a = -1; + if (a == -1 or C.a == -1) return crt(-1, 0); + T lcm = m/g*C.m; + T ans = a + (x*(C.a-a)/g % (C.m/g))*m; + return crt((ans % lcm + lcm) % lcm, lcm); + } +}; + +pair divide_show(ll n, int p, int k, int pak) { + if (n == 0) return {0, 1}; + ll blocos = n/pak, falta = n%pak; + ll periodo = divi[pak], resto = divi[falta]; + ll r = expo(periodo, blocos, pak)*resto%pak; + + auto rec = divide_show(n/p, p, k, pak); + ll y = n/p + rec.first; + r = r*rec.second % pak; + + return {y, r}; +} + +ll solve_pak(ll n, ll x, int p, int k, int pak) { + divi[0] = 1; + for (int i = 1; i <= pak; i++) { + divi[i] = divi[i-1]; + if (i%p) divi[i] = divi[i] * i % pak; + } + + auto dn = divide_show(n, p, k, pak), dx = divide_show(x, p, k, pak), + dnx = divide_show(n-x, p, k, pak); + ll y = dn.first-dx.first-dnx.first, r = + (dn.second*inv(dx.second, pak)%pak)*inv(dnx.second, pak)%pak; + return expo(p, y, pak) * r % pak; +} + +ll solve(ll n, ll x, int mod) { + vector> f; + int mod2 = mod; + for (int i = 2; i*i <= mod2; i++) if (mod2%i==0) { + int c = 0; + while (mod2%i==0) mod2 /= i, c++; + f.push_back({i, c}); + } + if (mod2 > 1) f.push_back({mod2, 1}); + crt ans(0, 1); + for (int i = 0; i < f.size(); i++) { + int pak = 1; + for (int j = 0; j < f[i].second; j++) pak *= f[i].first; + ans = ans * crt(solve_pak(n, x, f[i].first, f[i].second, pak), pak); + } + return ans.a; +} +``` diff --git a/content/docs/Problemas/closestPairOfPoints.md b/content/docs/Problemas/closestPairOfPoints.md new file mode 100644 index 0000000..8f681c8 --- /dev/null +++ b/content/docs/Problemas/closestPairOfPoints.md @@ -0,0 +1,53 @@ +--- +weight: 10 +title: "Closest pair of points" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + O(nlogn) + + + +Link original: [closestPairOfPoints.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/closestPairOfPoints.cpp) + +## Código +```cpp +pair closest_pair_of_points(vector v) { + int n = v.size(); + sort(v.begin(), v.end()); + for (int i = 1; i < n; i++) if (v[i] == v[i-1]) return {v[i-1], v[i]}; + auto cmp_y = [&](const pt &l, const pt &r) { + if (l.y != r.y) return l.y < r.y; + return l.x < r.x; + }; + set s(cmp_y); + int l = 0, r = -1; + ll d2_min = numeric_limits::max(); + pt pl, pr; + const int magic = 5; + while (r+1 < n) { + auto it = s.insert(v[++r]).first; + int cnt = magic/2; + while (cnt-- and it != s.begin()) it--; + cnt = 0; + while (cnt++ < magic and it != s.end()) { + if (!((*it) == v[r])) { + ll d2 = dist2(*it, v[r]); + if (d2_min > d2) { + d2_min = d2; + pl = *it; + pr = v[r]; + } + } + it++; + } + while (l < r and sq(v[l].x-v[r].x) > d2_min) s.erase(v[l++]); + } + return {pl, pr}; +} +``` diff --git a/content/docs/Problemas/conectividadeDinamica.md b/content/docs/Problemas/conectividadeDinamica.md new file mode 100644 index 0000000..dba7f96 --- /dev/null +++ b/content/docs/Problemas/conectividadeDinamica.md @@ -0,0 +1,81 @@ +--- +weight: 10 +title: "Conectividade Dinamica DC" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Offline com Divide and Conquer e + + DSU com rollback + + O(n log^2(n)) + + + +Link original: [conectividadeDinamica.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/conectividadeDinamica.cpp) + +## Código +```cpp +typedef pair T; + +namespace data { + int n, ans; + int p[MAX], sz[MAX]; + stack S; + + void build(int n2) { + n = n2; + for (int i = 0; i < n; i++) p[i] = i, sz[i] = 1; + ans = n; + } + int find(int k) { + while (p[k] != k) k = p[k]; + return k; + } + void add(T x) { + int a = x.first, b = x.second; + a = find(a), b = find(b); + if (a == b) return S.push(-1); + ans--; + if (sz[a] > sz[b]) swap(a, b); + S.push(a); + sz[b] += sz[a]; + p[a] = b; + } + int query() { + return ans; + } + void rollback() { + int u = S.top(); S.pop(); + if (u == -1) return; + sz[p[u]] -= sz[u]; + p[u] = u; + ans++; + } +}; + +int ponta[MAX]; // outra ponta do intervalo ou -1 se for query +int ans[MAX], n, q; +T qu[MAX]; + +void solve(int l = 0, int r = q-1) { + if (l >= r) { + ans[l] = data::query(); // agora a estrutura ta certa + return; + } + int m = (l+r)/2, qnt = 1; + for (int i = m+1; i <= r; i++) if (ponta[i]+1 and ponta[i] < l) + data::add(qu[i]), qnt++; + solve(l, m); + while (--qnt) data::rollback(); + for (int i = l; i <= m; i++) if (ponta[i]+1 and ponta[i] > r) + data::add(qu[i]), qnt++; + solve(m+1, r); + while (qnt--) data::rollback(); +} +``` diff --git a/content/docs/Problemas/conectividadeDinamica2.md b/content/docs/Problemas/conectividadeDinamica2.md new file mode 100644 index 0000000..864718d --- /dev/null +++ b/content/docs/Problemas/conectividadeDinamica2.md @@ -0,0 +1,152 @@ +--- +weight: 10 +title: "Conectividade Dinamica LCT" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Offline com link-cut trees + + O(n log(n)) + + + +Link original: [conectividadeDinamica2.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/conectividadeDinamica2.cpp) + +## Código +```cpp +namespace lct { + struct node { + int p, ch[2]; + int val, sub; + bool rev; + node() {} + node(int v) : p(-1), val(v), sub(v), rev(0) { ch[0] = ch[1] = -1; } + }; + + node t[2*MAX]; // MAXN + MAXQ + map, int> aresta; + int sz; + + void prop(int x) { + if (t[x].rev) { + swap(t[x].ch[0], t[x].ch[1]); + if (t[x].ch[0]+1) t[t[x].ch[0]].rev ^= 1; + if (t[x].ch[1]+1) t[t[x].ch[1]].rev ^= 1; + } + t[x].rev = 0; + } + void update(int x) { + t[x].sub = t[x].val; + for (int i = 0; i < 2; i++) if (t[x].ch[i]+1) { + prop(t[x].ch[i]); + t[x].sub = min(t[x].sub, t[t[x].ch[i]].sub); + } + } + bool is_root(int x) { + return t[x].p == -1 or (t[t[x].p].ch[0] != x and t[t[x].p].ch[1] != x); + } + void rotate(int x) { + int p = t[x].p, pp = t[p].p; + if (!is_root(p)) t[pp].ch[t[pp].ch[1] == p] = x; + bool d = t[p].ch[0] == x; + t[p].ch[!d] = t[x].ch[d], t[x].ch[d] = p; + if (t[p].ch[!d]+1) t[t[p].ch[!d]].p = p; + t[x].p = pp, t[p].p = x; + update(p), update(x); + } + int splay(int x) { + while (!is_root(x)) { + int p = t[x].p, pp = t[p].p; + if (!is_root(p)) prop(pp); + prop(p), prop(x); + if (!is_root(p)) rotate((t[pp].ch[0] == p)^(t[p].ch[0] == x) ? x : p); + rotate(x); + } + return prop(x), x; + } + int access(int v) { + int last = -1; + for (int w = v; w+1; update(last = w), splay(v), w = t[v].p) + splay(w), t[w].ch[1] = (last == -1 ? -1 : v); + return last; + } + void make_tree(int v, int w=INF) { t[v] = node(w); } + bool conn(int v, int w) { + access(v), access(w); + return v == w ? true : t[v].p != -1; + } + void rootify(int v) { + access(v); + t[v].rev ^= 1; + } + int query(int v, int w) { + rootify(w), access(v); + return t[v].sub; + } + void link_(int v, int w) { + rootify(w); + t[w].p = v; + } + void link(int v, int w, int x) { // v--w com peso x + int id = MAX + sz++; + aresta[make_pair(v, w)] = id; + make_tree(id, x); + link_(v, id), link_(id, w); + } + void cut_(int v, int w) { + rootify(w), access(v); + t[v].ch[0] = t[t[v].ch[0]].p = -1; + } + void cut(int v, int w) { + int id = aresta[make_pair(v, w)]; + cut_(v, id), cut_(id, w); + } +} + +void dyn_conn() { + int n, q; cin >> n >> q; + vector p(2*q, -1); // outra ponta do intervalo + for (int i = 0; i < n; i++) lct::make_tree(i); + vector> qu(q); + map, int> m; + for (int i = 0; i < q; i++) { + char c; cin >> c; + if (c == '?') continue; + int a, b; cin >> a >> b; a--, b--; + if (a > b) swap(a, b); + qu[i] = {a, b}; + if (c == '+') { + p[i] = i+q, p[i+q] = i; + m[make_pair(a, b)] = i; + } else { + int j = m[make_pair(a, b)]; + p[i] = j, p[j] = i; + } + } + int ans = n; + for (int i = 0; i < q; i++) { + if (p[i] == -1) { + cout << ans << endl; // numero de comp conexos + continue; + } + int a = qu[i].first, b = qu[i].second; + if (p[i] > i) { // + + if (lct::conn(a, b)) { + int mi = lct::query(a, b); + if (p[i] < mi) { + p[p[i]] = p[i]; + continue; + } + lct::cut(qu[p[mi]].first, qu[p[mi]].second), ans++; + p[mi] = mi; + } + lct::link(a, b, p[i]), ans--; + } else if (p[i] != i) lct::cut(a, b), ans++; // - + } +} +``` diff --git a/content/docs/Problemas/deBrujin.md b/content/docs/Problemas/deBrujin.md new file mode 100644 index 0000000..8f055e5 --- /dev/null +++ b/content/docs/Problemas/deBrujin.md @@ -0,0 +1,53 @@ +--- +weight: 10 +title: "Sequencia de de Brujin" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Se passar sem o terceiro parametro, gera um vetor com valores + + em [0, k) de tamanho k^n de forma que todos os subarrays ciclicos + + de tamanho n ocorrem exatamente uma vez + + Se passar com um limite lim, gera o menor vetor com valores + + em [0, k) que possui lim subarrays de tamanho n distintos + + (assume que lim <= k^n) + + + + Linear no tamanho da resposta + + + +Link original: [deBrujin.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/deBrujin.cpp) + +## Código +```cpp +vector de_brujin(int n, int k, int lim = INF) { + if (k == 1) return vector(lim == INF ? 1 : n, 0); + vector l = {0}, ret; // l eh lyndon word + while (true) { + if (l.size() == 0) { + if (lim == INF) break; + l.push_back(0); + } + if (n % l.size() == 0) for (int i : l) { + ret.push_back(i); + if (ret.size() == n+lim-1) return ret; + } + int p = l.size(); + while (l.size() < n) l.push_back(l[l.size()%p]); + while (l.size() and l.back() == k-1) l.pop_back(); + if (l.size()) l.back()++; + } + return ret; +} +``` diff --git a/content/docs/Problemas/delaunay.md b/content/docs/Problemas/delaunay.md new file mode 100644 index 0000000..48f06da --- /dev/null +++ b/content/docs/Problemas/delaunay.md @@ -0,0 +1,169 @@ +--- +weight: 10 +title: "Triangulacao de Delaunay" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Computa a triangulacao de Delaunay, o dual + + do diagrama de Voronoi (a menos de casos degenerados) + + Retorna um grafo indexado pelos indices dos pontos, e as arestas + + sao as arestas da triangulacao + + As arestas partindo de um vertice ja vem ordenadas por angulo, + + ou seja, se o vertice v nao esta no convex hull, (v, v_i, v_{i+1}) + + eh um triangulo da triangulacao, em que v_i eh o i-esimo vizinho + + Usa o alg d&c, precisa representar MAX_COOR^4, por isso __int128 + + pra aguentar valores ateh 1e9 + + + + Propriedades: + + 1 - O grafo tem no max 3n-6 arestas + + 2 - Para todo triangulo, a circunf. que passa pelos 3 pontos + + nao contem estritamente nenhum ponto + + 3 - A MST euclidiana eh subgrafo desse grafo + + 4 - Cada ponto eh vizinho do ponto mais proximo dele + + + + O(n log n) + + + +Link original: [delaunay.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/delaunay.cpp) + +## Código +```cpp +typedef struct QuadEdge* Q; +struct QuadEdge { + int id; + pt o; + Q rot, nxt; + bool used; + + QuadEdge(int id_ = -1, pt o_ = pt(INF, INF)) : + id(id_), o(o_), rot(nullptr), nxt(nullptr), used(false) {} + + Q rev() const { return rot->rot; } + Q next() const { return nxt; } + Q prev() const { return rot->next()->rot; } + pt dest() const { return rev()->o; } +}; + +Q edge(pt from, pt to, int id_from, int id_to) { + Q e1 = new QuadEdge(id_from, from); + Q e2 = new QuadEdge(id_to, to); + Q e3 = new QuadEdge; + Q e4 = new QuadEdge; + tie(e1->rot, e2->rot, e3->rot, e4->rot) = {e3, e4, e2, e1}; + tie(e1->nxt, e2->nxt, e3->nxt, e4->nxt) = {e1, e2, e4, e3}; + return e1; +} + +void splice(Q a, Q b) { + swap(a->nxt->rot->nxt, b->nxt->rot->nxt); + swap(a->nxt, b->nxt); +} + +void del_edge(Q& e, Q ne) { // delete e and assign e <- ne + splice(e, e->prev()); + splice(e->rev(), e->rev()->prev()); + delete e->rev()->rot, delete e->rev(); + delete e->rot; delete e; + e = ne; +} + +Q conn(Q a, Q b) { + Q e = edge(a->dest(), b->o, a->rev()->id, b->id); + splice(e, a->rev()->prev()); + splice(e->rev(), b); + return e; +} + +bool in_c(pt a, pt b, pt c, pt p) { // p ta na circunf. (a, b, c) ? + __int128 p2 = p*p, A = a*a - p2, B = b*b - p2, C = c*c - p2; + return sarea2(p, a, b) * C + sarea2(p, b, c) * A + sarea2(p, c, a) * B > 0; +} + +pair build_tr(vector& p, int l, int r) { + if (r-l+1 <= 3) { + Q a = edge(p[l], p[l+1], l, l+1), b = edge(p[l+1], p[r], l+1, r); + if (r-l+1 == 2) return {a, a->rev()}; + splice(a->rev(), b); + ll ar = sarea2(p[l], p[l+1], p[r]); + Q c = ar ? conn(b, a) : 0; + if (ar >= 0) return {a, b->rev()}; + return {c->rev(), c}; + } + int m = (l+r)/2; + auto [la, ra] = build_tr(p, l, m); + auto [lb, rb] = build_tr(p, m+1, r); + while (true) { + if (ccw(lb->o, ra->o, ra->dest())) ra = ra->rev()->prev(); + else if (ccw(lb->o, ra->o, lb->dest())) lb = lb->rev()->next(); + else break; + } + Q b = conn(lb->rev(), ra); + auto valid = [&](Q e) { return ccw(e->dest(), b->dest(), b->o); }; + if (ra->o == la->o) la = b->rev(); + if (lb->o == rb->o) rb = b; + while (true) { + Q L = b->rev()->next(); + if (valid(L)) while (in_c(b->dest(), b->o, L->dest(), L->next()->dest())) + del_edge(L, L->next()); + Q R = b->prev(); + if (valid(R)) while (in_c(b->dest(), b->o, R->dest(), R->prev()->dest())) + del_edge(R, R->prev()); + if (!valid(L) and !valid(R)) break; + if (!valid(L) or (valid(R) and in_c(L->dest(), L->o, R->o, R->dest()))) + b = conn(R, b->rev()); + else b = conn(b->rev(), L->rev()); + } + return {la, rb}; +} + +vector> delaunay(vector v) { + int n = v.size(); + auto tmp = v; + vector idx(n); + iota(idx.begin(), idx.end(), 0); + sort(idx.begin(), idx.end(), [&](int l, int r) { return v[l] < v[r]; }); + for (int i = 0; i < n; i++) v[i] = tmp[idx[i]]; + assert(unique(v.begin(), v.end()) == v.end()); + vector> g(n); + bool col = true; + for (int i = 2; i < n; i++) if (sarea2(v[i], v[i-1], v[i-2])) col = false; + if (col) { + for (int i = 1; i < n; i++) + g[idx[i-1]].push_back(idx[i]), g[idx[i]].push_back(idx[i-1]); + return g; + } + Q e = build_tr(v, 0, n-1).first; + vector edg = {e}; + for (int i = 0; i < edg.size(); e = edg[i++]) { + for (Q at = e; !at->used; at = at->next()) { + at->used = true; + g[idx[at->id]].push_back(idx[at->rev()->id]); + edg.push_back(at->rev()); + } + } + return g; +} +``` diff --git a/content/docs/Problemas/distinct.md b/content/docs/Problemas/distinct.md new file mode 100644 index 0000000..8cc894b --- /dev/null +++ b/content/docs/Problemas/distinct.md @@ -0,0 +1,45 @@ +--- +weight: 10 +title: "Distinct Range Query" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + build - O(n (log n + log(sigma))) + + query - O(log(sigma)) + + + +Link original: [distinct.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/distinct.cpp) + +## Código +```cpp +namespace perseg { }; + +int qt[MAX]; + +void build(vector& v) { + int n = v.size(); + perseg::build(n); + map last; + int at = 0; + for (int i = 0; i < n; i++) { + if (last.count(v[i])) { + perseg::update(last[v[i]], -1); + at++; + } + perseg::update(i, 1); + qt[i] = ++at; + last[v[i]] = i; + } +} + +int query(int l, int r) { + return perseg::query(l, r, qt[r]); +} +``` diff --git a/content/docs/Problemas/distinctUpdate.md b/content/docs/Problemas/distinctUpdate.md new file mode 100644 index 0000000..7691a40 --- /dev/null +++ b/content/docs/Problemas/distinctUpdate.md @@ -0,0 +1,113 @@ +--- +weight: 10 +title: "Distinct Range Query com Update" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + build - O(n log(n)) + + query - O(log^2(n)) + + update - O(log^2(n)) + + + +Link original: [distinctUpdate.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/distinctUpdate.cpp) + +## Código +```cpp +#include +#include +using namespace __gnu_pbds; +template + using ord_set = tree, rb_tree_tag, + tree_order_statistics_node_update>; + +int v[MAX], n, nxt[MAX], prv[MAX]; +map > ocor; + +namespace bit { + ord_set> bit[MAX]; + + void build() { + for (int i = 1; i <= n; i++) bit[i].insert({nxt[i-1], i-1}); + for (int i = 1; i <= n; i++) { + int j = i + (i&-i); + if (j <= n) for (auto x : bit[i]) bit[j].insert(x); + } + } + int pref(int p, int x) { + int ret = 0; + for (; p; p -= p&-p) ret += bit[p].order_of_key({x, -INF}); + return ret; + } + int query(int l, int r, int x) { + return pref(r+1, x) - pref(l, x); + } + void update(int p, int x) { + int p2 = p; + for (p++; p <= n; p += p&-p) { + bit[p].erase({nxt[p2], p2}); + bit[p].insert({x, p2}); + } + } +} + +void build() { + for (int i = 0; i < n; i++) nxt[i] = INF; + for (int i = 0; i < n; i++) prv[i] = -INF; + vector> t; + for (int i = 0; i < n; i++) t.push_back({v[i], i}); + sort(t.begin(), t.end()); + for (int i = 0; i < n; i++) { + if (i and t[i].first == t[i-1].first) + prv[t[i].second] = t[i-1].second; + if (i+1 < n and t[i].first == t[i+1].first) + nxt[t[i].second] = t[i+1].second; + } + + for (int i = 0; i < n; i++) ocor[v[i]].insert(i); + + bit::build(); +} + +void muda(int p, int x) { + bit::update(p, x); + nxt[p] = x; +} + +int query(int a, int b) { + return b-a+1 - bit::query(a, b, b+1); +} + +void update(int p, int x) { // mudar valor na pos. p para x + if (prv[p] > -INF) muda(prv[p], nxt[p]); + if (nxt[p] < INF) prv[nxt[p]] = prv[p]; + + ocor[v[p]].erase(p); + if (!ocor[x].size()) { + muda(p, INF); + prv[p] = -INF; + } else if (*ocor[x].rbegin() < p) { + int i = *ocor[x].rbegin(); + prv[p] = i; + muda(p, INF); + muda(i, p); + } else { + int i = *ocor[x].lower_bound(p); + if (prv[i] > -INF) { + muda(prv[i], p); + prv[p] = prv[i]; + } else prv[p] = -INF; + prv[i] = p; + muda(p, i); + } + v[p] = x; ocor[x].insert(p); +} + +``` diff --git a/content/docs/Problemas/dominacao3d.md b/content/docs/Problemas/dominacao3d.md new file mode 100644 index 0000000..110a7b2 --- /dev/null +++ b/content/docs/Problemas/dominacao3d.md @@ -0,0 +1,90 @@ +--- +weight: 10 +title: "DP de Dominacao 3D" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Computa para todo ponto i, + + dp[i] = 1 + max_{j dominado por i} dp[j] + + em que ser dominado eh ter as 3 coordenadas menores + + Da pra adaptar facil para outras dps + + + + O(n log^2 n), O(n) de memoria + + + +Link original: [dominacao3d.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/dominacao3d.cpp) + +## Código +```cpp +void lis2d(vector>>& v, vector& dp, int l, int r) { + if (l == r) { + for (int i = 0; i < v[l].size(); i++) { + int ii = get<2>(v[l][i]); + dp[ii] = max(dp[ii], 1); + } + return; + } + int m = (l+r)/2; + lis2d(v, dp, l, m); + + vector> vv[2]; + vector Z; + for (int i = l; i <= r; i++) for (auto it : v[i]) { + vv[i > m].push_back(it); + Z.push_back(get<1>(it)); + } + sort(vv[0].begin(), vv[0].end()); + sort(vv[1].begin(), vv[1].end()); + sort(Z.begin(), Z.end()); + auto get_z = [&](int z) { return lower_bound(Z.begin(), Z.end(), z) - Z.begin(); }; + vector bit(Z.size()); + + int i = 0; + for (auto [y, z, id] : vv[1]) { + while (i < vv[0].size() and get<0>(vv[0][i]) < y) { + auto [y2, z2, id2] = vv[0][i++]; + for (int p = get_z(z2)+1; p <= Z.size(); p += p&-p) + bit[p-1] = max(bit[p-1], dp[id2]); + } + int q = 0; + for (int p = get_z(z); p; p -= p&-p) q = max(q, bit[p-1]); + dp[id] = max(dp[id], q + 1); + } + lis2d(v, dp, m+1, r); +} + +vector solve(vector> v) { + int n = v.size(); + vector> vv; + for (int i = 0; i < n; i++) { + auto [x, y, z] = v[i]; + vv.emplace_back(x, y, z, i); + } + sort(vv.begin(), vv.end()); + + vector>> V; + for (int i = 0; i < n; i++) { + int j = i; + V.emplace_back(); + while (j < n and get<0>(vv[j]) == get<0>(vv[i])) { + auto [x, y, z, id] = vv[j++]; + V.back().emplace_back(y, z, id); + } + i = j-1; + } + vector dp(n); + lis2d(V, dp, 0, V.size()-1); + return dp; +} +``` diff --git a/content/docs/Problemas/dominatorPoints.md b/content/docs/Problemas/dominatorPoints.md new file mode 100644 index 0000000..633541b --- /dev/null +++ b/content/docs/Problemas/dominatorPoints.md @@ -0,0 +1,84 @@ +--- +weight: 10 +title: "Dominator Points" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Se um ponto A tem ambas as coordenadas >= B, dizemos + + que A domina B + + is_dominated(p) fala se existe algum ponto no conjunto + + que domina p + + insert(p) insere p no conjunto + + (se p for dominado por alguem, nao vai inserir) + + o multiset 'quina' guarda informacao sobre os pontos + + nao dominados por um elemento do conjunto que nao dominam + + outro ponto nao dominado por um elemento do conjunto + + No caso, armazena os valores de x+y esses pontos + + + + Complexidades: + + is_dominated - O(log(n)) + + insert - O(log(n)) amortizado + + query - O(1) + + + +Link original: [dominatorPoints.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/dominatorPoints.cpp) + +## Código +```cpp +struct dominator_points { + set> se; + multiset quina; + + bool is_dominated(pair p) { + auto it = se.lower_bound(p); + if (it == se.end()) return 0; + return it->second >= p.second; + } + void mid(pair a, pair b, bool rem) { + pair m = {a.first+1, b.second+1}; + int val = m.first + m.second; + if (!rem) quina.insert(val); + else quina.erase(quina.find(val)); + } + bool insert(pair p) { + if (is_dominated(p)) return 0; + auto it = se.lower_bound(p); + if (it != se.begin() and it != se.end()) + mid(*prev(it), *it, 1); + while (it != se.begin()) { + it--; + if (it->second > p.second) break; + if (it != se.begin()) mid(*prev(it), *it, 1); + it = se.erase(it); + } + it = se.insert(p).first; + if (it != se.begin()) mid(*prev(it), *it, 0); + if (next(it) != se.end()) mid(*it, *next(it), 0); + return 1; + } + int query() { + if (!quina.size()) return INF; + return *quina.begin(); + } +}; +``` diff --git a/content/docs/Problemas/dynamicHull.md b/content/docs/Problemas/dynamicHull.md new file mode 100644 index 0000000..669fe90 --- /dev/null +++ b/content/docs/Problemas/dynamicHull.md @@ -0,0 +1,62 @@ +--- +weight: 10 +title: "Convex Hull Dinamico" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + insert - O(log n) amortizado + + is_inside - O(log n) + + + +Link original: [dynamicHull.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/dynamicHull.cpp) + +## Código +```cpp +struct upper { + set se; + set::iterator it; + + int is_under(pt p) { // 1 -> inside ; 2 -> border + it = se.lower_bound(p); + if (it == se.end()) return 0; + if (it == se.begin()) return p == *it ? 2 : 0; + if (ccw(p, *it, *prev(it))) return 1; + return ccw(p, *prev(it), *it) ? 0 : 2; + } + void insert(pt p) { + if (is_under(p)) return; + + if (it != se.end()) while (next(it) != se.end() and !ccw(*next(it), *it, p)) + it = se.erase(it); + if (it != se.begin()) while (--it != se.begin() and !ccw(p, *it, *prev(it))) + it = se.erase(it); + + se.insert(p); + } +}; + +struct dyn_hull { + upper U, L; + + int is_inside(pt p) { + int u = U.is_under(p), l = L.is_under({-p.x, -p.y}); + if (!u or !l) return 0; + return max(u, l); + } + void insert(pt p) { + U.insert(p); + L.insert({-p.x, -p.y}); + } + int size() { + int ans = U.se.size() + L.se.size(); + return ans <= 2 ? ans/2 : ans-2; + } +}; +``` diff --git a/content/docs/Problemas/graphTriangles.md b/content/docs/Problemas/graphTriangles.md new file mode 100644 index 0000000..8c35a25 --- /dev/null +++ b/content/docs/Problemas/graphTriangles.md @@ -0,0 +1,44 @@ +--- +weight: 10 +title: "Triangulos em Grafos" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + get_triangles(i) encontra todos os triangulos ijk no grafo + + Custo nas arestas + + retorna {custo do triangulo, {j, k}} + + + + O(m sqrt(m) log(n)) se chamar para todos os vertices + + + +Link original: [graphTriangles.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/graphTriangles.cpp) + +## Código +```cpp +vector> g[MAX]; // {para, peso} + +#warning o 'g' deve estar ordenado +vector>> get_triangles(int i) { + vector>> tri; + for (pair j : g[i]) { + int a = i, b = j.first; + if (g[a].size() > g[b].size()) swap(a, b); + for (pair c : g[a]) if (c.first != b and c.first > j.first) { + auto it = lower_bound(g[b].begin(), g[b].end(), make_pair(c.first, -INF)); + if (it == g[b].end() or it->first != c.first) continue; + tri.push_back({j.second+c.second+it->second, {a == i ? b : a, c.first}}); + } + } + return tri; +} +``` diff --git a/content/docs/Problemas/grayCode.md b/content/docs/Problemas/grayCode.md new file mode 100644 index 0000000..46efb37 --- /dev/null +++ b/content/docs/Problemas/grayCode.md @@ -0,0 +1,31 @@ +--- +weight: 10 +title: "Gray Code" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Gera uma permutacao de 0 a 2^n-1, de forma que + + duas posicoes adjacentes diferem em exatamente 1 bit + + + + O(2^n) + + + +Link original: [grayCode.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/grayCode.cpp) + +## Código +```cpp +vector gray_code(int n) { + vector ret(1<>1); + return ret; +} +``` diff --git a/content/docs/Problemas/halfPlaneIntersection.md b/content/docs/Problemas/halfPlaneIntersection.md new file mode 100644 index 0000000..8e0927a --- /dev/null +++ b/content/docs/Problemas/halfPlaneIntersection.md @@ -0,0 +1,46 @@ +--- +weight: 10 +title: "Half-plane intersection" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Cada half-plane eh identificado por uma reta e a regiao ccw a ela + + + + O(n log n) + + + +Link original: [halfPlaneIntersection.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/halfPlaneIntersection.cpp) + +## Código +```cpp +vector hp_intersection(vector &v) { + deque dq = {{INF, INF}, {-INF, INF}, {-INF, -INF}, {INF, -INF}}; + +#warning considerar trocar por compare_angle + sort(v.begin(), v.end(), [&](line r, line s) { return angle(r.q-r.p) < angle(s.q-s.p); }); + + for(int i = 0; i < v.size() and dq.size() > 1; i++) { + pt p1 = dq.front(), p2 = dq.back(); + while (dq.size() and !ccw(v[i].p, v[i].q, dq.back())) + p1 = dq.back(), dq.pop_back(); + while (dq.size() and !ccw(v[i].p, v[i].q, dq.front())) + p2 = dq.front(), dq.pop_front(); + + if (!dq.size()) break; + if (p1 == dq.front() and p2 == dq.back()) continue; + dq.push_back(inter(v[i], line(dq.back(), p1))); + dq.push_front(inter(v[i], line(dq.front(), p2))); + + if (dq.size() > 1 and dq.back() == dq.front()) dq.pop_back(); + } + return vector(dq.begin(), dq.end()); +} +``` diff --git a/content/docs/Problemas/heapSort.md b/content/docs/Problemas/heapSort.md new file mode 100644 index 0000000..623884f --- /dev/null +++ b/content/docs/Problemas/heapSort.md @@ -0,0 +1,33 @@ +--- +weight: 10 +title: "Heap Sort" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + O(n log n) + + + +Link original: [heapSort.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/heapSort.cpp) + +## Código +```cpp +void down(vector& v, int n, int i) { + while ((i = 2*i+1) < n) { + if (i+1 < n and v[i] < v[i+1]) i++; + if (v[i] < v[(i-1)/2]) break; + swap(v[i], v[(i-1)/2]); + } +} +void heap_sort(vector& v) { + int n = v.size(); + for (int i = n/2-1; i >= 0; i--) down(v, n, i); + for (int i = n-1; i > 0; i--) + swap(v[0], v[i]), down(v, i, 0); +} +``` diff --git a/content/docs/Problemas/hungarian.md b/content/docs/Problemas/hungarian.md new file mode 100644 index 0000000..e004a23 --- /dev/null +++ b/content/docs/Problemas/hungarian.md @@ -0,0 +1,72 @@ +--- +weight: 10 +title: "Hungaro" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Resolve o problema de assignment (matriz n x n) + + Colocar os valores da matriz em 'a' (pode < 0) + + assignment() retorna um par com o valor do + + assignment minimo, e a coluna escolhida por cada linha + + + + O(n^3) + + + +Link original: [hungarian.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/hungarian.cpp) + +## Código +```cpp +template struct hungarian { + int n; + vector> a; + vector u, v; + vector p, way; + T inf; + + hungarian(int n_) : n(n_), u(n+1), v(n+1), p(n+1), way(n+1) { + a = vector>(n, vector(n)); + inf = numeric_limits::max(); + } + pair> assignment() { + for (int i = 1; i <= n; i++) { + p[0] = i; + int j0 = 0; + vector minv(n+1, inf); + vector used(n+1, 0); + do { + used[j0] = true; + int i0 = p[j0], j1 = -1; + T delta = inf; + for (int j = 1; j <= n; j++) if (!used[j]) { + T cur = a[i0-1][j-1] - u[i0] - v[j]; + if (cur < minv[j]) minv[j] = cur, way[j] = j0; + if (minv[j] < delta) delta = minv[j], j1 = j; + } + for (int j = 0; j <= n; j++) + if (used[j]) u[p[j]] += delta, v[j] -= delta; + else minv[j] -= delta; + j0 = j1; + } while (p[j0] != 0); + do { + int j1 = way[j0]; + p[j0] = p[j1]; + j0 = j1; + } while (j0); + } + vector ans(n); + for (int j = 1; j <= n; j++) ans[p[j]-1] = j-1; + return make_pair(-v[0], ans); + } +}; +``` diff --git a/content/docs/Problemas/intervalGraphColoring.md b/content/docs/Problemas/intervalGraphColoring.md new file mode 100644 index 0000000..9bb93cb --- /dev/null +++ b/content/docs/Problemas/intervalGraphColoring.md @@ -0,0 +1,48 @@ +--- +weight: 10 +title: "Coloracao de Grafo de Intervalo" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Colore os intervalos com o numero minimo + + de cores de tal forma que dois intervalos + + que se interceptam tem cores diferentes + + As cores vao de 1 ate n + + + + O(n log(n)) + + + +Link original: [intervalGraphColoring.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/intervalGraphColoring.cpp) + +## Código +```cpp +vector coloring(vector>& v) { + int n = v.size(); + vector>> ev; + for (int i = 0; i < n; i++) { + ev.push_back({v[i].first, {1, i}}); + ev.push_back({v[i].second, {0, i}}); + } + sort(ev.begin(), ev.end()); + vector ans(n), avl(n); + for (int i = 0; i < n; i++) avl.push_back(n-i); + for (auto i : ev) { + if (i.second.first == 1) { + ans[i.second.second] = avl.back(); + avl.pop_back(); + } else avl.push_back(ans[i.second.second]); + } + return ans; +} +``` diff --git a/content/docs/Problemas/intervalGraphIndSet.md b/content/docs/Problemas/intervalGraphIndSet.md new file mode 100644 index 0000000..350e752 --- /dev/null +++ b/content/docs/Problemas/intervalGraphIndSet.md @@ -0,0 +1,62 @@ +--- +weight: 10 +title: "Conj. Indep. Maximo com Peso em Grafo de Intervalo" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Retorna os indices ordenados dos intervalos selecionados + + Se tiver empate, retorna o que minimiza o comprimento total + + + + O(n log(n)) + + + +Link original: [intervalGraphIndSet.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/intervalGraphIndSet.cpp) + +## Código +```cpp +vector ind_set(vector>& v) { + vector> w; + for (int i = 0; i < v.size(); i++) { + w.push_back(tuple(get<0>(v[i]), 0, i)); + w.push_back(tuple(get<1>(v[i]), 1, i)); + } + sort(w.begin(), w.end()); + + vector nxt(v.size()); + vector> dp(v.size()); + int last = -1; + for (auto [fim, t, i] : w) { + if (t == 0) { + nxt[i] = last; + continue; + } + dp[i] = {0, 0}; + if (last != -1) dp[i] = max(dp[i], dp[last]); + pair pega = {get<2>(v[i]), -(get<1>(v[i]) - get<0>(v[i]) + 1)}; + if (nxt[i] != -1) pega.first += dp[nxt[i]].first, pega.second += dp[nxt[i]].second; + if (pega > dp[i]) dp[i] = pega; + else nxt[i] = last; + last = i; + } + pair ans = {0, 0}; + int idx = -1; + for (int i = 0; i < v.size(); i++) if (dp[i] > ans) ans = dp[i], idx = i; + vector ret; + while (idx != -1) { + if (get<2>(v[idx]) > 0 and + (nxt[idx] == -1 or get<1>(v[nxt[idx]]) < get<0>(v[idx]))) ret.push_back(idx); + idx = nxt[idx]; + } + sort(ret.begin(), ret.end()); + return ret; +} +``` diff --git a/content/docs/Problemas/inversionCount.md b/content/docs/Problemas/inversionCount.md new file mode 100644 index 0000000..b31aa36 --- /dev/null +++ b/content/docs/Problemas/inversionCount.md @@ -0,0 +1,50 @@ +--- +weight: 10 +title: "Inversion Count" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Computa o numero de inversoes para transformar + + l em r (se nao tem como, retorna -1) + + + + O(n log(n)) + + + +Link original: [inversionCount.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/inversionCount.cpp) + +## Código +```cpp +template ll inv_count(vector l, vector r = {}) { + if (!r.size()) { + r = l; + sort(r.begin(), r.end()); + } + int n = l.size(); + vector v(n), bit(n); + vector> w; + for (int i = 0; i < n; i++) w.push_back({r[i], i+1}); + sort(w.begin(), w.end()); + for (int i = 0; i < n; i++) { + auto it = lower_bound(w.begin(), w.end(), make_pair(l[i], 0)); + if (it == w.end() or it->first != l[i]) return -1; // nao da + v[i] = it->second; + it->second = -1; + } + + ll ans = 0; + for (int i = n-1; i >= 0; i--) { + for (int j = v[i]-1; j; j -= j&-j) ans += bit[j]; + for (int j = v[i]; j < n; j += j&-j) bit[j]++; + } + return ans; +} +``` diff --git a/content/docs/Problemas/lis.md b/content/docs/Problemas/lis.md new file mode 100644 index 0000000..d1d2154 --- /dev/null +++ b/content/docs/Problemas/lis.md @@ -0,0 +1,46 @@ +--- +weight: 10 +title: "LIS - recupera" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Calcula e retorna uma LIS + + + + O(n.log(n)) + + + +Link original: [lis.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/lis.cpp) + +## Código +```cpp +template vector lis(vector& v) { + int n = v.size(), m = -1; + vector d(n+1, INF); + vector l(n); + d[0] = -INF; + + for (int i = 0; i < n; i++) { + // Para non-decreasing use upper_bound() + int t = lower_bound(d.begin(), d.end(), v[i]) - d.begin(); + d[t] = v[i], l[i] = t, m = max(m, t); + } + + int p = n; + vector ret; + while (p--) if (l[p] == m) { + ret.push_back(v[p]); + m--; + } + reverse(ret.begin(),ret.end()); + + return ret; +} +``` diff --git a/content/docs/Problemas/lis2.md b/content/docs/Problemas/lis2.md new file mode 100644 index 0000000..1d5e134 --- /dev/null +++ b/content/docs/Problemas/lis2.md @@ -0,0 +1,34 @@ +--- +weight: 10 +title: "LIS - tamanho" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Calcula o tamanho da LIS + + + + O(n log(n)) + + + +Link original: [lis2.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/lis2.cpp) + +## Código +```cpp +template int lis(vector &v){ + vector ans; + for (T t : v){ + // Para non-decreasing use upper_bound() + auto it = lower_bound(ans.begin(), ans.end(), t); + if (it == ans.end()) ans.push_back(t); + else *it = t; + } + return ans.size(); +} +``` diff --git a/content/docs/Problemas/maxDist.md b/content/docs/Problemas/maxDist.md new file mode 100644 index 0000000..ba11a7f --- /dev/null +++ b/content/docs/Problemas/maxDist.md @@ -0,0 +1,49 @@ +--- +weight: 10 +title: "Distancia maxima entre dois pontos" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + max_dist2(v) - O(n log(n)) + + max_dist_manhattan - O(n) + + + + Quadrado da Distancia Euclidiana (precisa copiar convex_hull, ccw e pt) + +Link original: [maxDist.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/maxDist.cpp) + +## Código +```cpp +ll max_dist2(vector v) { + v = convex_hull(v); + if (v.size() <= 2) return dist2(v[0], v[1%v.size()]); + ll ans = 0; + int n = v.size(), j = 0; + for (int i = 0; i < n; i++) { + while (!ccw(v[(i+1)%n]-v[i], pt(0, 0), v[(j+1)%n]-v[j])) j = (j+1)%n; + ans = max({ans, dist2(v[i], v[j]), dist2(v[(i+1)%n], v[j])}); + } + return ans; +} + +// Distancia de Manhattan +template T max_dist_manhattan(vector> v) { + T min_sum, max_sum, min_dif, max_dif; + min_sum = max_sum = v[0].first + v[0].second; + min_dif = max_dif = v[0].first - v[0].second; + for (auto [x, y] : v) { + min_sum = min(min_sum, x+y); + max_sum = max(max_sum, x+y); + min_dif = min(min_dif, x-y); + max_dif = max(max_dif, x-y); + } + return max(max_sum - min_sum, max_dif - min_dif); +} +``` diff --git a/content/docs/Problemas/minCirc.md b/content/docs/Problemas/minCirc.md new file mode 100644 index 0000000..e590bf3 --- /dev/null +++ b/content/docs/Problemas/minCirc.md @@ -0,0 +1,67 @@ +--- +weight: 10 +title: "Minimum Enclosing Circle" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + O(n) com alta probabilidade + + + +Link original: [minCirc.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/minCirc.cpp) + +## Código +```cpp +const double EPS = 1e-12; +mt19937 rng((int) chrono::steady_clock::now().time_since_epoch().count()); + +struct pt { + double x, y; + pt(double x_ = 0, double y_ = 0) : x(x_), y(y_) {} + pt operator + (const pt& p) const { return pt(x+p.x, y+p.y); } + pt operator - (const pt& p) const { return pt(x-p.x, y-p.y); } + pt operator * (double c) const { return pt(x*c, y*c); } + pt operator / (double c) const { return pt(x/c, y/c); } +}; + +double dot(pt p, pt q) { return p.x*q.x+p.y*q.y; } +double cross(pt p, pt q) { return p.x*q.y-p.y*q.x; } +double dist(pt p, pt q) { return sqrt(dot(p-q, p-q)); } + +pt center(pt p, pt q, pt r) { + pt a = p-r, b = q-r; + pt c = pt(dot(a, p+r)/2, dot(b, q+r)/2); + return pt(cross(c, pt(a.y, b.y)), cross(pt(a.x, b.x), c)) / cross(a, b); +} + +struct circle { + pt cen; + double r; + circle(pt cen_, double r_) : cen(cen_), r(r_) {} + circle(pt a, pt b, pt c) { + cen = center(a, b, c); + r = dist(cen, a); + } + bool inside(pt p) { return dist(p, cen) < r+EPS; } +}; + +circle minCirc(vector v) { + shuffle(v.begin(), v.end(), rng); + circle ret = circle(pt(0, 0), 0); + for (int i = 0; i < v.size(); i++) if (!ret.inside(v[i])) { + ret = circle(v[i], 0); + for (int j = 0; j < i; j++) if (!ret.inside(v[j])) { + ret = circle((v[i]+v[j])/2, dist(v[i], v[j])/2); + for (int k = 0; k < j; k++) if (!ret.inside(v[k])) + ret = circle(v[i], v[j], v[k]); + } + } + return ret; +} + +``` diff --git a/content/docs/Problemas/minkowski.md b/content/docs/Problemas/minkowski.md new file mode 100644 index 0000000..cd4d3ed --- /dev/null +++ b/content/docs/Problemas/minkowski.md @@ -0,0 +1,55 @@ +--- +weight: 10 +title: "Minkowski Sum" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Computa A+B = {a+b : a \in A, b \in B}, em que + + A e B sao poligonos convexos + + A+B eh um poligono convexo com no max |A|+|B| pontos + + + + O(|A|+|B|) + + + +Link original: [minkowski.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/minkowski.cpp) + +## Código +```cpp +vector minkowski(vector p, vector q) { + auto fix = [](vector& P) { + rotate(P.begin(), min_element(P.begin(), P.end()), P.end()); + P.push_back(P[0]), P.push_back(P[1]); + }; + fix(p), fix(q); + vector ret; + int i = 0, j = 0; + while (i < p.size()-2 or j < q.size()-2) { + ret.push_back(p[i] + q[j]); + auto c = ((p[i+1] - p[i]) ^ (q[j+1] - q[j])); + if (c >= 0) i = min(i+1, p.size()-2); + if (c <= 0) j = min(j+1, q.size()-2); + } + return ret; +} + +ld dist_convex(vector p, vector q) { + for (pt& i : p) i = i * -1; + auto s = minkowski(p, q); + if (inpol(s, pt(0, 0))) return 0; + return 1; + ld ans = DINF; + for (int i = 0; i < s.size(); i++) ans = min(ans, + disttoseg(pt(0, 0), line(s[(i+1)%s.size()], s[i]))); + return ans; +} +``` diff --git a/content/docs/Problemas/mo.md b/content/docs/Problemas/mo.md new file mode 100644 index 0000000..48f782d --- /dev/null +++ b/content/docs/Problemas/mo.md @@ -0,0 +1,90 @@ +--- +weight: 10 +title: "MO" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Para ter o bound abaixo, escolher + + SQ = n / sqrt(q) + + + + O(n * sqrt(q)) + + + +Link original: [mo.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/mo.cpp) + +## Código +```cpp +const int MAX = 1e5+10; +const int SQ = sqrt(MAX); +int v[MAX]; + +int ans, freq[MAX]; + +inline void insert(int p) { + int o = v[p]; + freq[o]++; + ans += (freq[o] == 1); +} + +inline void erase(int p) { + int o = v[p]; + ans -= (freq[o] == 1); + freq[o]--; +} + +inline ll hilbert(int x, int y) { + static int N = 1 << (__builtin_clz(0) - __builtin_clz(MAX)); + int rx, ry, s; + ll d = 0; + for (s = N/2; s > 0; s /= 2) { + rx = (x & s) > 0, ry = (y & s) > 0; + d += s * ll(s) * ((3 * rx) ^ ry); + if (ry == 0) { + if (rx == 1) x = N-1 - x, y = N-1 - y; + swap(x, y); + } + } + return d; +} + +#define HILBERT true +vector MO(vector> &q) { + ans = 0; + int m = q.size(); + vector ord(m); + iota(ord.begin(), ord.end(), 0); +#if HILBERT + vector h(m); + for (int i = 0; i < m; i++) h[i] = hilbert(q[i].first, q[i].second); + sort(ord.begin(), ord.end(), [&](int l, int r) { return h[l] < h[r]; }); +#else + sort(ord.begin(), ord.end(), [&](int l, int r) { + if (q[l].first / SQ != q[r].first / SQ) return q[l].first < q[r].first; + if ((q[l].first / SQ) % 2) return q[l].second > q[r].second; + return q[l].second < q[r].second; + }); +#endif + vector ret(m); + int l = 0, r = -1; + + for (int i : ord) { + int ql, qr; + tie(ql, qr) = q[i]; + while (r < qr) insert(++r); + while (l > ql) insert(--l); + while (l < ql) erase(l++); + while (r > qr) erase(r--); + ret[i] = ans; + } + return ret; +} +``` diff --git a/content/docs/Problemas/moDsu.md b/content/docs/Problemas/moDsu.md new file mode 100644 index 0000000..06e8822 --- /dev/null +++ b/content/docs/Problemas/moDsu.md @@ -0,0 +1,108 @@ +--- +weight: 10 +title: "MO - DSU" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Dado uma lista de arestas de um grafo, responde + + para cada query(l, r), quantos componentes conexos + + o grafo tem se soh considerar as arestas l, l+1, ..., r + + Da pra adaptar pra usar MO com qualquer estrutura rollbackavel + + + + O(m sqrt(q) log(n)) + + + +Link original: [moDsu.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/moDsu.cpp) + +## Código +```cpp +struct dsu { + int n, ans; + vector p, sz; + stack S; + + dsu(int n_) : n(n_), ans(n), p(n), sz(n) { + for (int i = 0; i < n; i++) p[i] = i, sz[i] = 1; + } + int find(int k) { + while (p[k] != k) k = p[k]; + return k; + } + void add(pair x) { + int a = x.first, b = x.second; + a = find(a), b = find(b); + if (a == b) return S.push(-1); + ans--; + if (sz[a] > sz[b]) swap(a, b); + S.push(a); + sz[b] += sz[a]; + p[a] = b; + } + int query() { return ans; } + void rollback() { + int u = S.top(); S.pop(); + if (u == -1) return; + sz[p[u]] -= sz[u]; + p[u] = u; + ans++; + } +}; + +int n; +vector> ar; + +// 9d242b +vector MO(vector> &q) { + int SQ = sqrt(q.size()) + 1; + int m = q.size(); + vector ord(m); + iota(ord.begin(), ord.end(), 0); + sort(ord.begin(), ord.end(), [&](int l, int r) { + if (q[l].first / SQ != q[r].first / SQ) return q[l].first < q[r].first; + return q[l].second < q[r].second; + }); + vector ret(m); + + dsu small(n); + for (int i = 0; i < m; i++) { + auto [l, r] = q[ord[i]]; + if (l / SQ == r / SQ) { + for (int k = l; k <= r; k++) small.add(ar[k]); + ret[ord[i]] = small.query(); + for (int k = l; k <= r; k++) small.rollback(); + } + } + + for (int i = 0; i < m; i++) { + dsu D(n); + int fim = q[ord[i]].first/SQ*SQ + SQ - 1; + int last_r = fim; + int j = i-1; + while (j+1 < m and q[ord[j+1]].first / SQ == q[ord[i]].first / SQ) { + auto [l, r] = q[ord[++j]]; + + if (l / SQ == r / SQ) continue; + + while (last_r < r) D.add(ar[++last_r]); + for (int k = l; k <= fim; k++) D.add(ar[k]); + + ret[ord[j]] = D.query(); + + for (int k = l; k <= fim; k++) D.rollback(); + } + i = j; + } + return ret; +} +``` diff --git a/content/docs/Problemas/moOnTrees.md b/content/docs/Problemas/moOnTrees.md new file mode 100644 index 0000000..b6c8f64 --- /dev/null +++ b/content/docs/Problemas/moOnTrees.md @@ -0,0 +1,107 @@ +--- +weight: 10 +title: "MO em Arvores" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Problema que resolve: https://www.spoj.com/problems/COT2/ + + + + Complexidade sendo c = O(update) e SQ = sqrt(n): + + O((n + q) * sqrt(n) * c) + + + +Link original: [moOnTrees.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/moOnTrees.cpp) + +## Código +```cpp +const int MAX = 40010, SQ = 400; + +vector g[MAX]; + +namespace LCA { ... } + +int in[MAX], out[MAX], vtx[2 * MAX]; +bool on[MAX]; + +int dif, freq[MAX]; +vector w; + +void dfs(int v, int p, int &t) { + vtx[t] = v, in[v] = t++; + for (int u : g[v]) if (u != p) { + dfs(u, v, t); + } + vtx[t] = v, out[v] = t++; +} + +void update(int p) { // faca alteracoes aqui + int v = vtx[p]; + if (not on[v]) { // insere vtx v + dif += (freq[w[v]] == 0); + freq[w[v]]++; + } + else { // retira o vertice v + dif -= (freq[w[v]] == 1); + freq[w[v]]--; + } + on[v] = not on[v]; +} + +vector> build_queries(const vector>& q) { + LCA::build(0); + vector> ret; + for (auto [l, r] : q){ + if (in[r] < in[l]) swap(l, r); + int p = LCA::lca(l, r); + int init = (p == l) ? in[l] : out[l]; + ret.emplace_back(init, in[r], in[p]); + } + return ret; +} + +vector mo_tree(const vector>& vq){ + int t = 0; + dfs(0, -1, t); + + auto q = build_queries(vq); + + vector ord(q.size()); + iota(ord.begin(), ord.end(), 0); + sort(ord.begin(), ord.end(), [&] (int l, int r) { + int bl = get<0>(q[l]) / SQ, br = get<0>(q[r]) / SQ; + if (bl != br) return bl < br; + else if (bl % 2 == 1) return get<1>(q[l]) < get<1>(q[r]); + else return get<1>(q[l]) > get<1>(q[r]); + }); + + memset(freq, 0, sizeof freq); + dif = 0; + + vector ret(q.size()); + int l = 0, r = -1; + for (int i : ord) { + auto [ql, qr, qp] = q[i]; + while (r < qr) update(++r); + while (l > ql) update(--l); + while (l < ql) update(l++); + while (r > qr) update(r--); + + if (qp < l or qp > r) { // se LCA estah entre as pontas + update(qp); + ret[i] = dif; + update(qp); + } + else ret[i] = dif; + } + return ret; +} +``` diff --git a/content/docs/Problemas/palindromicFactorization.md b/content/docs/Problemas/palindromicFactorization.md new file mode 100644 index 0000000..be6504b --- /dev/null +++ b/content/docs/Problemas/palindromicFactorization.md @@ -0,0 +1,54 @@ +--- +weight: 10 +title: "Palindromic Factorization" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Precisa da eertree + + Computa o numero de formas de particionar cada + + prefixo da string em strings palindromicas + + + + O(n log n), considerando alfabeto O(1) + + + +Link original: [palindromicFactorization.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/palindromicFactorization.cpp) + +## Código +```cpp +struct eertree { ... }; + +ll factorization(string s) { + int n = s.size(), sz = 2; + eertree PT(n); + vector diff(n+2), slink(n+2), sans(n+2), dp(n+1); + dp[0] = 1; + for (int i = 1; i <= n; i++) { + PT.add(s[i-1]); + if (PT.size()+2 > sz) { + diff[sz] = PT.len[sz] - PT.len[PT.link[sz]]; + if (diff[sz] == diff[PT.link[sz]]) + slink[sz] = slink[PT.link[sz]]; + else slink[sz] = PT.link[sz]; + sz++; + } + for (int v = PT.last; PT.len[v] > 0; v = slink[v]) { + sans[v] = dp[i - (PT.len[slink[v]] + diff[v])]; + if (diff[v] == diff[PT.link[v]]) + sans[v] = (sans[v] + sans[PT.link[v]]) % MOD; + dp[i] = (dp[i] + sans[v]) % MOD; + } + } + return dp[n]; +} + +``` diff --git a/content/docs/Problemas/parsing.md b/content/docs/Problemas/parsing.md new file mode 100644 index 0000000..a569672 --- /dev/null +++ b/content/docs/Problemas/parsing.md @@ -0,0 +1,103 @@ +--- +weight: 10 +title: "Parsing de Expressao" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Operacoes associativas a esquerda por default + + Para mudar isso, colocar em r_assoc + + Operacoes com maior prioridade sao feitas primeiro + + + +Link original: [parsing.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/parsing.cpp) + +## Código +```cpp +bool blank(char c) { + return c == ' '; +} + +bool is_unary(char c) { + return c == '+' or c == '-'; +} + +bool is_op(char c) { + if (is_unary(c)) return true; + return c == '*' or c == '/' or c == '+' or c == '-'; +} + +bool r_assoc(char op) { + // operator unario - deve ser assoc. a direita + return op < 0; +} + +int priority(char op) { + // operator unario - deve ter precedencia maior + if (op < 0) return INF; + + if (op == '*' or op == '/') return 2; + if (op == '+' or op == '-') return 1; + return -1; +} + +void process_op(stack& st, stack& op) { + char o = op.top(); op.pop(); + if (o < 0) { + o *= -1; + int l = st.top(); st.pop(); + if (o == '+') st.push(l); + if (o == '-') st.push(-l); + } else { + int r = st.top(); st.pop(); + int l = st.top(); st.pop(); + if (o == '*') st.push(l * r); + if (o == '/') st.push(l / r); + if (o == '+') st.push(l + r); + if (o == '-') st.push(l - r); + } +} + +int eval(string& s) { + stack st, op; + bool un = true; + for (int i = 0; i < s.size(); i++) { + if (blank(s[i])) continue; + + if (s[i] == '(') { + op.push('('); + un = true; + } else if (s[i] == ')') { + while (op.top() != '(') process_op(st, op); + op.pop(); + un = false; + } else if (is_op(s[i])) { + char o = s[i]; + if (un and is_unary(o)) o *= -1; + while (op.size() and ( + (!r_assoc(o) and priority(op.top()) >= priority(o)) or + (r_assoc(o) and priority(op.top()) > priority(o)))) + process_op(st, op); + op.push(o); + un = true; + } else { + int val = 0; + while (i < s.size() and isalnum(s[i])) + val = val * 10 + s[i++] - '0'; + i--; + st.push(val); + un = false; + } + } + + while (op.size()) process_op(st, op); + return st.top(); +} +``` diff --git a/content/docs/Problemas/rmqOffline.md b/content/docs/Problemas/rmqOffline.md new file mode 100644 index 0000000..99a37cb --- /dev/null +++ b/content/docs/Problemas/rmqOffline.md @@ -0,0 +1,45 @@ +--- +weight: 10 +title: "RMQ com Divide and Conquer" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Responde todas as queries em + + O(n log(n)) + + + +Link original: [rmqOffline.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/rmqOffline.cpp) + +## Código +```cpp +typedef pair, int> iii; +#define f first +#define s second + +int n, q, v[MAX]; +iii qu[MAX]; +int ans[MAX], pref[MAX], sulf[MAX]; + +void solve(int l=0, int r=n-1, int ql=0, int qr=q-1) { + if (l > r or ql > qr) return; + int m = (l+r)/2; + int qL = partition(qu+ql, qu+qr+1, [=](iii x){return x.f.s < m;}) - qu; + int qR = partition(qu+qL, qu+qr+1, [=](iii x){return x.f.f <=m;}) - qu; + + pref[m] = sulf[m] = v[m]; + for (int i = m-1; i >= l; i--) pref[i] = min(v[i], pref[i+1]); + for (int i = m+1; i <= r; i++) sulf[i] = min(v[i], sulf[i-1]); + + for (int i = qL; i < qR; i++) + ans[qu[i].s] = min(pref[qu[i].f.f], sulf[qu[i].f.s]); + + solve(l, m-1, ql, qL-1), solve(m+1, r, qR, qr); +} +``` diff --git a/content/docs/Problemas/segmentIntersection.md b/content/docs/Problemas/segmentIntersection.md new file mode 100644 index 0000000..a08f217 --- /dev/null +++ b/content/docs/Problemas/segmentIntersection.md @@ -0,0 +1,61 @@ +--- +weight: 10 +title: "Segment Intersection" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Verifica, dado n segmentos, se existe algum par de segmentos + + que se intersecta + + + + O(n log n) + + + +Link original: [segmentIntersection.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/segmentIntersection.cpp) + +## Código +```cpp +bool operator < (const line& a, const line& b) { // comparador pro sweepline + if (a.p == b.p) return ccw(a.p, a.q, b.q); + if (!eq(a.p.x, a.q.x) and (eq(b.p.x, b.q.x) or a.p.x+eps < b.p.x)) + return ccw(a.p, a.q, b.p); + return ccw(a.p, b.q, b.p); +} + +bool has_intersection(vector v) { + auto intersects = [&](pair a, pair b) { + return interseg(a.first, b.first); + }; + vector>> w; + for (int i = 0; i < v.size(); i++) { + if (v[i].q < v[i].p) swap(v[i].p, v[i].q); + w.push_back({v[i].p, {0, i}}); + w.push_back({v[i].q, {1, i}}); + } + sort(w.begin(), w.end()); + set> se; + for (auto i : w) { + line at = v[i.second.second]; + if (i.second.first == 0) { + auto nxt = se.lower_bound({at, i.second.second}); + if (nxt != se.end() and intersects(*nxt, {at, i.second.second})) return 1; + if (nxt != se.begin() and intersects(*(--nxt), {at, i.second.second})) return 1; + se.insert({at, i.second.second}); + } else { + auto nxt = se.upper_bound({at, i.second.second}), cur = nxt, prev = --cur; + if (nxt != se.end() and prev != se.begin() + and intersects(*nxt, *(--prev))) return 1; + se.erase(cur); + } + } + return 0; +} +``` diff --git a/content/docs/Problemas/simplePolygon.md b/content/docs/Problemas/simplePolygon.md new file mode 100644 index 0000000..b675d01 --- /dev/null +++ b/content/docs/Problemas/simplePolygon.md @@ -0,0 +1,67 @@ +--- +weight: 10 +title: "Simple Polygon" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Verifica se um poligono com n pontos eh simples + + + + O(n log n) + + + +Link original: [simplePolygon.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/simplePolygon.cpp) + +## Código +```cpp +bool operator < (const line& a, const line& b) { // comparador pro sweepline + if (a.p == b.p) return ccw(a.p, a.q, b.q); + if (!eq(a.p.x, a.q.x) and (eq(b.p.x, b.q.x) or a.p.x+eps < b.p.x)) + return ccw(a.p, a.q, b.p); + return ccw(a.p, b.q, b.p); +} + +bool simple(vector v) { + auto intersects = [&](pair a, pair b) { + if ((a.second+1)%v.size() == b.second or + (b.second+1)%v.size() == a.second) return false; + return interseg(a.first, b.first); + }; + vector seg; + vector>> w; + for (int i = 0; i < v.size(); i++) { + pt at = v[i], nxt = v[(i+1)%v.size()]; + if (nxt < at) swap(at, nxt); + seg.push_back(line(at, nxt)); + w.push_back({at, {0, i}}); + w.push_back({nxt, {1, i}}); + // casos degenerados estranhos + if (isinseg(v[(i+2)%v.size()], line(at, nxt))) return 0; + if (isinseg(v[(i+v.size()-1)%v.size()], line(at, nxt))) return 0; + } + sort(w.begin(), w.end()); + set> se; + for (auto i : w) { + line at = seg[i.second.second]; + if (i.second.first == 0) { + auto nxt = se.lower_bound({at, i.second.second}); + if (nxt != se.end() and intersects(*nxt, {at, i.second.second})) return 0; + if (nxt != se.begin() and intersects(*(--nxt), {at, i.second.second})) return 0; + se.insert({at, i.second.second}); + } else { + auto nxt = se.upper_bound({at, i.second.second}), cur = nxt, prev = --cur; + if (nxt != se.end() and prev != se.begin() + and intersects(*nxt, *(--prev))) return 0; + se.erase(cur); + } + } + return 1; +} +``` diff --git a/content/docs/Problemas/steinerTree.md b/content/docs/Problemas/steinerTree.md new file mode 100644 index 0000000..304780f --- /dev/null +++ b/content/docs/Problemas/steinerTree.md @@ -0,0 +1,110 @@ +--- +weight: 10 +title: "Steiner Tree" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + steiner: retorna o peso da menor arvore que cobre os vertices S + + get_steiner: retorna o valor minimo e as arestas de uma solucao + + se nao tiver solucao retorna LINF + + + + grafo nao pode ter pesos negativos + + se so tiver peso nas arestas/vertices pode deletar os vw/w no codigo + + + + k = |S| + + O(3^k * n + 2^k * m log m) + + + + otimizacao: joga um vertice x do S fora e pegue a resposta em dp[...][x] e reconstrua a arvore a partir dele + + ta comentado no codigo as mudancas necessarias + + + +Link original: [steinerTree.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/steinerTree.cpp) + +## Código +```cpp +int n; // numero de vertices +vector> g[MAX]; // {vizinho, peso} +ll d[1 << K][MAX]; // dp[mask][v] = arvore minima com o subconjunto mask de S e o vertice v +ll vw[MAX]; // peso do vertice + +ll steiner(const vector &S) { + int k = S.size(); // k--; + for (int mask = 0; mask < (1 << k); mask++) for(int v = 0; v < n; v++) d[mask][v] = LINF; + for (int v = 0; v < n; v++) d[0][v] = vw[v]; + for (int i = 0; i < k; ++i) d[1 << i][S[i]] = vw[S[i]]; + for (int mask = 1; mask < (1 << k); mask++) { + for (int a = (mask - 1) & mask; a; a = (a - 1) & mask) { + int b = mask ^ a; + if (b > a) break; + for (int v = 0; v < n; v++) + d[mask][v] = min(d[mask][v], d[a][v] + d[b][v] - vw[v]); + } + priority_queue> pq; + for (int v = 0; v < n; v++) { + if (d[mask][v] == LINF) continue; + pq.emplace(-d[mask][v], v); + } + while (pq.size()) { + auto [ndist, u] = pq.top(); pq.pop(); + if (-ndist > d[mask][u]) continue; + for (auto [idx, w] : g[u]) if (d[mask][idx] > d[mask][u] + w + vw[idx]) { + d[mask][idx] = d[mask][u] + w + vw[idx]; + pq.emplace(-d[mask][idx], idx); + } + } + } + return d[(1 << k) - 1][S[0]]; // S[k] +} + +#warning se k=1 a solucao eh a folha isolada e a funcao retorna edg = {} +#warning se k=0 crasha +pair>> get_steiner(const vector &S) { + int k = S.size(); // k--; + ll ans = steiner(S); + vector> edg; + stack> stk; + stk.emplace((1 << k) - 1, S[0]); // S[k] + while (!stk.empty()) { + bool cont = 0; + auto [mask,u] = stk.top();stk.pop(); + if ((__builtin_popcount(mask) == 1 and u == S[__bit_width(mask) - 1])) continue; + for (auto [idx, w] : g[u]){ + if (d[mask][u] == d[mask][idx] + w + vw[u]) { + edg.emplace_back(u, idx); + stk.emplace(mask, idx); + cont = true; + break; + } + } + if (cont) continue; + for (int a = (mask - 1) & mask; a; a = (a - 1) & mask) { + int b = mask ^ a; + if (d[mask][u] == d[a][u] + d[b][u] - vw[u]) { + stk.emplace(a, u); + stk.emplace(b, u); + cont = true; + break; + } + } + assert(!mask || cont); + } + return {ans, edg}; +} +``` diff --git a/content/docs/Problemas/sweepDirection.md b/content/docs/Problemas/sweepDirection.md new file mode 100644 index 0000000..690f095 --- /dev/null +++ b/content/docs/Problemas/sweepDirection.md @@ -0,0 +1,54 @@ +--- +weight: 10 +title: "Sweep Direction" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Passa por todas as ordenacoes dos pontos definitas por "direcoes" + + Assume que nao existem pontos coincidentes + + + + O(n^2 log n) + + + +Link original: [sweepDirection.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Problemas/sweepDirection.cpp) + +## Código +```cpp +void sweep_direction(vector v) { + int n = v.size(); + sort(v.begin(), v.end(), [](pt a, pt b) { + if (a.x != b.x) return a.x < b.x; + return a.y > b.y; + }); + vector at(n); + iota(at.begin(), at.end(), 0); + vector> swapp; + for (int i = 0; i < n; i++) for (int j = i+1; j < n; j++) + swapp.push_back({i, j}), swapp.push_back({j, i}); + + sort(swapp.begin(), swapp.end(), [&](auto a, auto b) { + pt A = rotate90(v[a.first] - v[a.second]); + pt B = rotate90(v[b.first] - v[b.second]); + if (quad(A) == quad(B) and !sarea2(pt(0, 0), A, B)) return a < b; + return compare_angle(A, B); + }); + for (auto par : swapp) { + assert(abs(at[par.first] - at[par.second]) == 1); + int l = min(at[par.first], at[par.second]), + r = n-1 - max(at[par.first], at[par.second]); + // l e r sao quantos caras tem de cada lado do par de pontos + // (cada par eh visitado duas vezes) + swap(v[at[par.first]], v[at[par.second]]); + swap(at[par.first], at[par.second]); + } +} +``` diff --git a/content/docs/Strings/_index.md b/content/docs/Strings/_index.md new file mode 100644 index 0000000..b4de32b --- /dev/null +++ b/content/docs/Strings/_index.md @@ -0,0 +1,8 @@ +--- +weight: 10 +title: "Strings" +draft: false +date: "2024-05-09T17:19:25-0300" +description: "" +publishdate: "2024-05-09T17:19:25-0300" +--- diff --git a/content/docs/Strings/ahocorasick.md b/content/docs/Strings/ahocorasick.md new file mode 100644 index 0000000..782b476 --- /dev/null +++ b/content/docs/Strings/ahocorasick.md @@ -0,0 +1,70 @@ +--- +weight: 10 +title: "Aho-corasick" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + query retorna o somatorio do numero de matches de + + todas as stringuinhas na stringona + + + + insert - O(|s| log(SIGMA)) + + build - O(N), onde N = somatorio dos tamanhos das strings + + query - O(|s|) + + + +Link original: [ahocorasick.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Strings/ahocorasick.cpp) + +## Código +```cpp +namespace aho { + map to[MAX]; + int link[MAX], idx, term[MAX], exit[MAX], sobe[MAX]; + + void insert(string& s) { + int at = 0; + for (char c : s) { + auto it = to[at].find(c); + if (it == to[at].end()) at = to[at][c] = ++idx; + else at = it->second; + } + term[at]++, sobe[at]++; + } +#warning nao esquece de chamar build() depois de inserir + void build() { + queue q; + q.push(0); + link[0] = exit[0] = -1; + while (q.size()) { + int i = q.front(); q.pop(); + for (auto [c, j] : to[i]) { + int l = link[i]; + while (l != -1 and !to[l].count(c)) l = link[l]; + link[j] = l == -1 ? 0 : to[l][c]; + exit[j] = term[link[j]] ? link[j] : exit[link[j]]; + if (exit[j]+1) sobe[j] += sobe[exit[j]]; + q.push(j); + } + } + } + int query(string& s) { + int at = 0, ans = 0; + for (char c : s){ + while (at != -1 and !to[at].count(c)) at = link[at]; + at = at == -1 ? 0 : to[at][c]; + ans += sobe[at]; + } + return ans; + } +} +``` diff --git a/content/docs/Strings/dynamicSuffixArray.md b/content/docs/Strings/dynamicSuffixArray.md new file mode 100644 index 0000000..32ae5ca --- /dev/null +++ b/content/docs/Strings/dynamicSuffixArray.md @@ -0,0 +1,212 @@ +--- +weight: 10 +title: "Suffix Array Dinamico" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Mantem o suffix array, lcp e rank de uma string, + + premitindo push_front e pop_front + + O operador [i] return um par com sa[i] e lcp[i] + + lcp[i] tem o lcp entre sa[i] e sa[i-1] (lcp[0] = 0) + + + + Complexidades: + + Construir sobre uma string de tamanho n: O(n log n) + + push_front e pop_front: O(log n) amortizado + + + +Link original: [dynamicSuffixArray.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Strings/dynamicSuffixArray.cpp) + +## Código +```cpp +struct dyn_sa { + struct node { + int sa, lcp; + node *l, *r, *p; + int sz, mi; + node(int sa_, int lcp_, node* p_) : sa(sa_), lcp(lcp_), + l(NULL), r(NULL), p(p_), sz(1), mi(lcp) {} + void update() { + sz = 1, mi = lcp; + if (l) sz += l->sz, mi = min(mi, l->mi); + if (r) sz += r->sz, mi = min(mi, r->mi); + } + }; + + node* root; + vector tag; // tag of a suffix (reversed id) + string s; // reversed + + dyn_sa() : root(NULL) {} + dyn_sa(string s_) : dyn_sa() { + reverse(s_.begin(), s_.end()); + for (char c : s_) push_front(c); + } + ~dyn_sa() { + vector q = {root}; + while (q.size()) { + node* x = q.back(); q.pop_back(); + if (!x) continue; + q.push_back(x->l), q.push_back(x->r); + delete x; + } + } + + int size(node* x) { return x ? x->sz : 0; } + int mirror(int i) { return s.size()-1 - i; } + bool cmp(int i, int j) { + if (s[i] != s[j]) return s[i] < s[j]; + if (i == 0 or j == 0) return i < j; + return tag[i-1] < tag[j-1]; + } + void fix_path(node* x) { while (x) x->update(), x = x->p; } + void flatten(vector& v, node* x) { + if (!x) return; + flatten(v, x->l); + v.push_back(x); + flatten(v, x->r); + } + void build(vector& v, node*& x, node* p, int L, int R, ll l, ll r) { + if (L > R) return void(x = NULL); + int M = (L+R)/2; + ll m = (l+r)/2; + x = v[M]; + x->p = p; + tag[x->sa] = m; + build(v, x->l, x, L, M-1, l, m-1), build(v, x->r, x, M+1, R, m+1, r); + x->update(); + } + void fix(node*& x, node* p, ll l, ll r) { + if (3*max(size(x->l), size(x->r)) <= 2*size(x)) return x->update(); + vector v; + flatten(v, x); + build(v, x, p, 0, v.size()-1, l, r); + } + node* next(node* x) { + if (x->r) { + x = x->r; + while (x->l) x = x->l; + return x; + } + while (x->p and x->p->r == x) x = x->p; + return x->p; + } + node* prev(node* x) { + if (x->l) { + x = x->l; + while (x->r) x = x->r; + return x; + } + while (x->p and x->p->l == x) x = x->p; + return x->p; + } + + int get_lcp(node* x, node* y) { + if (!x or !y) return 0; // change defaut value here + if (s[x->sa] != s[y->sa]) return 0; + if (x->sa == 0 or y->sa == 0) return 1; + return 1 + query(mirror(x->sa-1), mirror(y->sa-1)); + } + void add_suf(node*& x, node* p, int id, ll l, ll r) { + if (!x) { + x = new node(id, 0, p); + node *prv = prev(x), *nxt = next(x); + int lcp_cur = get_lcp(prv, x), lcp_nxt = get_lcp(x, nxt); + if (nxt) nxt->lcp = lcp_nxt, fix_path(nxt); + x->lcp = lcp_cur; + tag[id] = (l+r)/2; + x->update(); + return; + } + if (cmp(id, x->sa)) add_suf(x->l, x, id, l, tag[x->sa]-1); + else add_suf(x->r, x, id, tag[x->sa]+1, r); + fix(x, p, l, r); + } + void push_front(char c) { + s += c; + tag.push_back(-1); + add_suf(root, NULL, s.size() - 1, 0, 1e18); + } + + void rem_suf(node*& x, int id) { + if (x->sa != id) { + if (tag[id] < tag[x->sa]) return rem_suf(x->l, id); + return rem_suf(x->r, id); + } + node* nxt = next(x); + if (nxt) nxt->lcp = min(nxt->lcp, x->lcp), fix_path(nxt); + + node *p = x->p, *tmp = x; + if (!x->l or !x->r) { + x = x->l ? x->l : x->r; + if (x) x->p = p; + } else { + for (tmp = x->l, p = x; tmp->r; tmp = tmp->r) p = tmp; + x->sa = tmp->sa, x->lcp = tmp->lcp; + if (tmp->l) tmp->l->p = p; + if (p->l == tmp) p->l = tmp->l; + else p->r = tmp->l; + } + fix_path(p); + delete tmp; + } + void pop_front() { + if (!s.size()) return; + s.pop_back(); + rem_suf(root, s.size()); + tag.pop_back(); + } + + int query(node* x, ll l, ll r, ll a, ll b) { + if (!x or tag[x->sa] == -1 or r < a or b < l) return s.size(); + if (a <= l and r <= b) return x->mi; + int ans = s.size(); + if (a <= tag[x->sa] and tag[x->sa] <= b) ans = min(ans, x->lcp); + ans = min(ans, query(x->l, l, tag[x->sa]-1, a, b)); + ans = min(ans, query(x->r, tag[x->sa]+1, r, a, b)); + return ans; + } + int query(int i, int j) { // lcp(s[i..], s[j..]) + if (i == j) return s.size() - i; + ll a = tag[mirror(i)], b = tag[mirror(j)]; + int ret = query(root, 0, 1e18, min(a, b)+1, max(a, b)); + return ret; + } + // optional: get rank[i], sa[i] and lcp[i] + int rank(int i) { + i = mirror(i); + node* x = root; + int ret = 0; + while (x) { + if (tag[x->sa] < tag[i]) { + ret += size(x->l)+1; + x = x->r; + } else x = x->l; + } + return ret; + } + pair operator[](int i) { + node* x = root; + while (1) { + if (i < size(x->l)) x = x->l; + else { + i -= size(x->l); + if (!i) return {mirror(x->sa), x->lcp}; + i--, x = x->r; + } + } + } +}; +``` diff --git a/content/docs/Strings/eertree.md b/content/docs/Strings/eertree.md new file mode 100644 index 0000000..2c4df27 --- /dev/null +++ b/content/docs/Strings/eertree.md @@ -0,0 +1,69 @@ +--- +weight: 10 +title: "eertree" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Constroi a eertree, caractere a caractere + + Inicializar com a quantidade de caracteres maxima + + size() retorna a quantidade de substrings pal. distintas + + depois de chamar propagate(), cada substring palindromica + + ocorre qt[i] vezes. O propagate() retorna o numero de + + substrings pal. com repeticao + + + + O(n) amortizado, considerando alfabeto O(1) + + + +Link original: [eertree.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Strings/eertree.cpp) + +## Código +```cpp +struct eertree { + vector> t; + int n, last, sz; + vector s, len, link, qt; + + eertree(int N) { + t = vector(N+2, vector(26, int())); + s = len = link = qt = vector(N+2); + s[0] = -1; + link[0] = 1, len[0] = 0, link[1] = 1, len[1] = -1; + sz = 2, last = 0, n = 1; + } + + void add(char c) { + s[n++] = c -= 'a'; + while (s[n-len[last]-2] != c) last = link[last]; + if (!t[last][c]) { + int prev = link[last]; + while (s[n-len[prev]-2] != c) prev = link[prev]; + link[sz] = t[prev][c]; + len[sz] = len[last]+2; + t[last][c] = sz++; + } + qt[last = t[last][c]]++; + } + int size() { return sz-2; } + ll propagate() { + ll ret = 0; + for (int i = n; i > 1; i--) { + qt[link[i]] += qt[i]; + ret += qt[i]; + } + return ret; + } +}; +``` diff --git a/content/docs/Strings/hashing.md b/content/docs/Strings/hashing.md new file mode 100644 index 0000000..09c61b8 --- /dev/null +++ b/content/docs/Strings/hashing.md @@ -0,0 +1,45 @@ +--- +weight: 10 +title: "String Hashing" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Complexidades: + + construtor - O(|s|) + + operator() - O(1) + + + +Link original: [hashing.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Strings/hashing.cpp) + +## Código +```cpp +mt19937 rng((int) chrono::steady_clock::now().time_since_epoch().count()); + +int uniform(int l, int r) { + uniform_int_distribution uid(l, r); + return uid(rng); +} + +template struct str_hash { // 116fcb + static int P; + vector h, p; + str_hash(string s) : h(s.size()), p(s.size()) { + p[0] = 1, h[0] = s[0]; + for (int i = 1; i < s.size(); i++) + p[i] = p[i - 1]*P%MOD, h[i] = (h[i - 1]*P + s[i])%MOD; + } + ll operator()(int l, int r) { // retorna hash s[l...r] + ll hash = h[r] - (l ? h[l - 1]*p[r - l + 1]%MOD : 0); + return hash < 0 ? hash + MOD : hash; + } +}; +template int str_hash::P = uniform(256, MOD - 1); // l > |sigma| +``` diff --git a/content/docs/Strings/hashingLargeMod.md b/content/docs/Strings/hashingLargeMod.md new file mode 100644 index 0000000..6804ff4 --- /dev/null +++ b/content/docs/Strings/hashingLargeMod.md @@ -0,0 +1,59 @@ +--- +weight: 10 +title: "String Hashing - modulo 2^61 - 1" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Quase duas vezes mais lento + + + + Complexidades: + + build - O(|s|) + + operator() - O(1) + + + +Link original: [hashingLargeMod.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Strings/hashingLargeMod.cpp) + +## Código +```cpp +const ll MOD = (1ll<<61) - 1; +ll mulmod(ll a, ll b) { + const static ll LOWER = (1ll<<30) - 1, GET31 = (1ll<<31) - 1; + ll l1 = a&LOWER, h1 = a>>30, l2 = b&LOWER, h2 = b>>30; + ll m = l1*h2 + l2*h1, h = h1*h2; + ll ans = l1*l2 + (h>>1) + ((h&1)<<60) + (m>>31) + ((m&GET31)<<30) + 1; + ans = (ans&MOD) + (ans>>61), ans = (ans&MOD) + (ans>>61); + return ans - 1; +} + +mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count()); + +ll uniform(ll l, ll r) { + uniform_int_distribution uid(l, r); + return uid(rng); +} + +struct str_hash { + static ll P; + vector h, p; + str_hash(string s) : h(s.size()), p(s.size()) { + p[0] = 1, h[0] = s[0]; + for (int i = 1; i < s.size(); i++) + p[i] = mulmod(p[i - 1], P), h[i] = (mulmod(h[i - 1], P) + s[i])%MOD; + } + ll operator()(int l, int r) { // retorna hash s[l...r] + ll hash = h[r] - (l ? mulmod(h[l - 1], p[r - l + 1]) : 0); + return hash < 0 ? hash + MOD : hash; + } +}; +ll str_hash::P = uniform(256, MOD - 1); // l > |sigma| +``` diff --git a/content/docs/Strings/kmp.md b/content/docs/Strings/kmp.md new file mode 100644 index 0000000..84bb2e6 --- /dev/null +++ b/content/docs/Strings/kmp.md @@ -0,0 +1,67 @@ +--- +weight: 10 +title: "KMP" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + matching(s, t) retorna os indices das ocorrencias + + de s em t + + autKMP constroi o automato do KMP + + + + Complexidades: + + pi - O(n) + + match - O(n + m) + + construir o automato - O(|sigma|*n) + + n = |padrao| e m = |texto| + + + +Link original: [kmp.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Strings/kmp.cpp) + +## Código +```cpp +template vector pi(T s) { + vector p(s.size()); + for (int i = 1, j = 0; i < s.size(); i++) { + while (j and s[j] != s[i]) j = p[j-1]; + if (s[j] == s[i]) j++; + p[i] = j; + } + return p; +} + +template vector matching(T& s, T& t) { + vector p = pi(s), match; + for (int i = 0, j = 0; i < t.size(); i++) { + while (j and s[j] != t[i]) j = p[j-1]; + if (s[j] == t[i]) j++; + if (j == s.size()) match.push_back(i-j+1), j = p[j-1]; + } + return match; +} + +struct KMPaut : vector> { + KMPaut(){} + KMPaut (string& s) : vector>(26, vector(s.size()+1)) { + vector p = pi(s); + auto& aut = *this; + aut[s[0]-'a'][0] = 1; + for (char c = 0; c < 26; c++) + for (int i = 1; i <= s.size(); i++) + aut[c][i] = s[i]-'a' == c ? i+1 : aut[c][p[i-1]]; + } +}; +``` diff --git a/content/docs/Strings/manacher.md b/content/docs/Strings/manacher.md new file mode 100644 index 0000000..8d59d05 --- /dev/null +++ b/content/docs/Strings/manacher.md @@ -0,0 +1,77 @@ +--- +weight: 10 +title: "Manacher" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + manacher recebe um vetor de T e retorna o vetor com tamanho dos palindromos + + ret[2*i] = tamanho do maior palindromo centrado em i + + ret[2*i+1] = tamanho maior palindromo centrado em i e i+1 + + + + Complexidades: + + manacher - O(n) + + palindrome - + + pal_end - O(n) + + + +Link original: [manacher.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Strings/manacher.cpp) + +## Código +```cpp +template vector manacher(const T& s) { + int l = 0, r = -1, n = s.size(); + vector d1(n), d2(n); + for (int i = 0; i < n; i++) { + int k = i > r ? 1 : min(d1[l+r-i], r-i); + while (i+k < n && i-k >= 0 && s[i+k] == s[i-k]) k++; + d1[i] = k--; + if (i+k > r) l = i-k, r = i+k; + } + l = 0, r = -1; + for (int i = 0; i < n; i++) { + int k = i > r ? 0 : min(d2[l+r-i+1], r-i+1); k++; + while (i+k <= n && i-k >= 0 && s[i+k-1] == s[i-k]) k++; + d2[i] = --k; + if (i+k-1 > r) l = i-k, r = i+k-1; + } + vector ret(2*n-1); + for (int i = 0; i < n; i++) ret[2*i] = 2*d1[i]-1; + for (int i = 0; i < n-1; i++) ret[2*i+1] = 2*d2[i+1]; + return ret; +} + +// verifica se a string s[i..j] eh palindromo +template struct palindrome { + vector man; + + palindrome(const T& s) : man(manacher(s)) {} + bool query(int i, int j) { + return man[i+j] >= j-i+1; + } +}; + +// tamanho do maior palindromo que termina em cada posicao +template vector pal_end(const T& s) { + vector ret(s.size()); + palindrome p(s); + ret[0] = 1; + for (int i = 1; i < s.size(); i++) { + ret[i] = min(ret[i-1]+2, i+1); + while (!p.query(i-ret[i]+1, i)) ret[i]--; + } + return ret; +} +``` diff --git a/content/docs/Strings/minMaxSuffixCyclic.md b/content/docs/Strings/minMaxSuffixCyclic.md new file mode 100644 index 0000000..9e6470f --- /dev/null +++ b/content/docs/Strings/minMaxSuffixCyclic.md @@ -0,0 +1,55 @@ +--- +weight: 10 +title: "Min/max suffix/cyclic shift" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Computa o indice do menor/maior sufixo/cyclic shift + + da string, lexicograficamente + + + + O(n) + + + +Link original: [minMaxSuffixCyclic.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Strings/minMaxSuffixCyclic.cpp) + +## Código +```cpp +template int max_suffix(T s, bool mi = false) { + s.push_back(*min_element(s.begin(), s.end())-1); + int ans = 0; + for (int i = 1; i < s.size(); i++) { + int j = 0; + while (ans+j < i and s[i+j] == s[ans+j]) j++; + if (s[i+j] > s[ans+j]) { + if (!mi or i != s.size()-2) ans = i; + } else if (j) i += j-1; + } + return ans; +} + +template int min_suffix(T s) { + for (auto& i : s) i *= -1; + s.push_back(*max_element(s.begin(), s.end())+1); + return max_suffix(s, true); +} + +template int max_cyclic_shift(T s) { + int n = s.size(); + for (int i = 0; i < n; i++) s.push_back(s[i]); + return max_suffix(s); +} + +template int min_cyclic_shift(T s) { + for (auto& i : s) i *= -1; + return max_cyclic_shift(s); +} +``` diff --git a/content/docs/Strings/suffixArray.md b/content/docs/Strings/suffixArray.md new file mode 100644 index 0000000..b682bcb --- /dev/null +++ b/content/docs/Strings/suffixArray.md @@ -0,0 +1,211 @@ +--- +weight: 10 +title: "Suffix Array - O(n)" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Rapidao + + Computa o suffix array em 'sa', o rank em 'rnk' + + e o lcp em 'lcp' + + query(i, j) retorna o LCP entre s[i..n-1] e s[j..n-1] + + + + Complexidades + + O(n) para construir + + query - O(1) + + + +Link original: [suffixArray.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Strings/suffixArray.cpp) + +## Código +```cpp +template struct rmq { + vector v; + int n; static const int b = 30; + vector mask, t; + + int op(int x, int y) { return v[x] <= v[y] ? x : y; } + int msb(int x) { return __builtin_clz(1)-__builtin_clz(x); } + int small(int r, int sz = b) { return r-msb(mask[r]&((1<& v_) : v(v_), n(v.size()), mask(n), t(n) { + for (int i = 0, at = 0; i < n; mask[i++] = at |= 1) { + at = (at<<1)&((1< y) return op(small(l+b-1), small(r)); + int j = msb(y-x+1); + int ans = op(small(l+b-1), op(t[n/b*j+x], t[n/b*j+y-(1< sa, cnt, rnk, lcp; + rmq RMQ; + + bool cmp(int a1, int b1, int a2, int b2, int a3=0, int b3=0) { + return a1 != b1 ? a1 < b1 : (a2 != b2 ? a2 < b2 : a3 < b3); + } + template void radix(int* fr, int* to, T* r, int N, int k) { + cnt = vector(k+1, 0); + for (int i = 0; i < N; i++) cnt[r[fr[i]]]++; + for (int i = 1; i <= k; i++) cnt[i] += cnt[i-1]; + for (int i = N-1; i+1; i--) to[--cnt[r[fr[i]]]] = fr[i]; + } + void rec(vector& v, int k) { + auto &tmp = rnk, &m0 = lcp; + int N = v.size()-3, sz = (N+2)/3, sz2 = sz+N/3; + vector R(sz2+3); + for (int i = 1, j = 0; j < sz2; i += i%3) R[j++] = i; + + radix(&R[0], &tmp[0], &v[0]+2, sz2, k); + radix(&tmp[0], &R[0], &v[0]+1, sz2, k); + radix(&R[0], &tmp[0], &v[0]+0, sz2, k); + + int dif = 0; + int l0 = -1, l1 = -1, l2 = -1; + for (int i = 0; i < sz2; i++) { + if (v[tmp[i]] != l0 or v[tmp[i]+1] != l1 or v[tmp[i]+2] != l2) + l0 = v[tmp[i]], l1 = v[tmp[i]+1], l2 = v[tmp[i]+2], dif++; + if (tmp[i]%3 == 1) R[tmp[i]/3] = dif; + else R[tmp[i]/3+sz] = dif; + } + + if (dif < sz2) { + rec(R, dif); + for (int i = 0; i < sz2; i++) R[sa[i]] = i+1; + } else for (int i = 0; i < sz2; i++) sa[R[i]-1] = i; + + for (int i = 0, j = 0; j < sz2; i++) if (sa[i] < sz) tmp[j++] = 3*sa[i]; + radix(&tmp[0], &m0[0], &v[0], sz, k); + for (int i = 0; i < sz2; i++) + sa[i] = sa[i] < sz ? 3*sa[i]+1 : 3*(sa[i]-sz)+2; + + int at = sz2+sz-1, p = sz-1, p2 = sz2-1; + while (p >= 0 and p2 >= 0) { + if ((sa[p2]%3==1 and cmp(v[m0[p]], v[sa[p2]], R[m0[p]/3], + R[sa[p2]/3+sz])) or (sa[p2]%3==2 and cmp(v[m0[p]], v[sa[p2]], + v[m0[p]+1], v[sa[p2]+1], R[m0[p]/3+sz], R[sa[p2]/3+1]))) + sa[at--] = sa[p2--]; + else sa[at--] = m0[p--]; + } + while (p >= 0) sa[at--] = m0[p--]; + if (N%3==1) for (int i = 0; i < N; i++) sa[i] = sa[i+1]; + } + + suffix_array(const string& s_) : s(s_), n(s.size()), sa(n+3), + cnt(n+1), rnk(n), lcp(n-1) { + vector v(n+3); + for (int i = 0; i < n; i++) v[i] = i; + radix(&v[0], &rnk[0], &s[0], n, 256); + int dif = 1; + for (int i = 0; i < n; i++) + v[rnk[i]] = dif += (i and s[rnk[i]] != s[rnk[i-1]]); + if (n >= 2) rec(v, dif); + sa.resize(n); + + for (int i = 0; i < n; i++) rnk[sa[i]] = i; + for (int i = 0, k = 0; i < n; i++, k -= !!k) { + if (rnk[i] == n-1) { + k = 0; + continue; + } + int j = sa[rnk[i]+1]; + while (i+k < n and j+k < n and s[i+k] == s[j+k]) k++; + lcp[rnk[i]] = k; + } + RMQ = rmq(lcp); + } + + int query(int i, int j) { + if (i == j) return n-i; + i = rnk[i], j = rnk[j]; + return RMQ.query(min(i, j), max(i, j)-1); + } + pair next(int L, int R, int i, char c) { + int l = L, r = R+1; + while (l < r) { + int m = (l+r)/2; + if (i+sa[m] >= n or s[i+sa[m]] < c) l = m+1; + else r = m; + } + if (l == R+1 or s[i+sa[l]] > c) return {-1, -1}; + L = l; + + l = L, r = R+1; + while (l < r) { + int m = (l+r)/2; + if (i+sa[m] >= n or s[i+sa[m]] <= c) l = m+1; + else r = m; + } + R = l-1; + return {L, R}; + } + // quantas vezes 't' ocorre em 's' - O(|t| log n) + int count_substr(string& t) { + int L = 0, R = n-1; + for (int i = 0; i < t.size(); i++) { + tie(L, R) = next(L, R, i, t[i]); + if (L == -1) return 0; + } + return R-L+1; + } + + // exemplo de f que resolve o problema + // https://codeforces.com/edu/course/2/lesson/2/5/practice/contest/269656/problem/D + ll f(ll k) { return k*(k+1)/2; } + + ll dfs(int L, int R, int p) { // dfs na suffix tree chamado em pre ordem + int ext = L != R ? RMQ.query(L, R-1) : n - sa[L]; + + // Tem 'ext - p' substrings diferentes que ocorrem 'R-L+1' vezes + // O LCP de todas elas eh 'ext' + ll ans = (ext-p)*f(R-L+1); + + // L eh terminal, e folha sse L == R + if (sa[L]+ext == n) L++; + + // se for um SA de varias strings separadas como s#t$u&, usar no lugar do if de cima + // (separadores < 'a', diferentes e inclusive no final) + // while (L <= R && (sa[L]+ext == n || s[sa[L]+ext] < 'a')) { + // L++; + // } + + while (L <= R) { + int idx = L != R ? RMQ.index_query(L, R-1) : -1; + if (idx == -1 or lcp[idx] != ext) idx = R; + + ans += dfs(L, idx, ext); + L = idx+1; + } + return ans; + } + + // sum over substrings: computa, para toda substring t distinta de s, + // \sum f(# ocorrencias de t em s) - O (n) + ll sos() { return dfs(0, n-1, 0); } +}; +``` diff --git a/content/docs/Strings/suffixArray2.md b/content/docs/Strings/suffixArray2.md new file mode 100644 index 0000000..053ecf4 --- /dev/null +++ b/content/docs/Strings/suffixArray2.md @@ -0,0 +1,64 @@ +--- +weight: 10 +title: "Suffix Array - O(n log n)" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + kasai recebe o suffix array e calcula lcp[i], + + o lcp entre s[sa[i],...,n-1] e s[sa[i+1],..,n-1] + + + + Complexidades: + + suffix_array - O(n log(n)) + + kasai - O(n) + + + +Link original: [suffixArray2.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Strings/suffixArray2.cpp) + +## Código +```cpp +vector suffix_array(string s) { + s += "$"; + int n = s.size(), N = max(n, 260); + vector sa(n), ra(n); + for(int i = 0; i < n; i++) sa[i] = i, ra[i] = s[i]; + + for(int k = 0; k < n; k ? k *= 2 : k++) { + vector nsa(sa), nra(n), cnt(N); + + for(int i = 0; i < n; i++) nsa[i] = (nsa[i]-k+n)%n, cnt[ra[i]]++; + for(int i = 1; i < N; i++) cnt[i] += cnt[i-1]; + for(int i = n-1; i+1; i--) sa[--cnt[ra[nsa[i]]]] = nsa[i]; + + for(int i = 1, r = 0; i < n; i++) nra[sa[i]] = r += ra[sa[i]] != + ra[sa[i-1]] or ra[(sa[i]+k)%n] != ra[(sa[i-1]+k)%n]; + ra = nra; + if (ra[sa[n-1]] == n-1) break; + } + return vector(sa.begin()+1, sa.end()); +} + +vector kasai(string s, vector sa) { + int n = s.size(), k = 0; + vector ra(n), lcp(n); + for (int i = 0; i < n; i++) ra[sa[i]] = i; + + for (int i = 0; i < n; i++, k -= !!k) { + if (ra[i] == n-1) { k = 0; continue; } + int j = sa[ra[i]+1]; + while (i+k < n and j+k < n and s[i+k] == s[j+k]) k++; + lcp[ra[i]] = k; + } + return lcp; +} +``` diff --git a/content/docs/Strings/suffixAutomaton.md b/content/docs/Strings/suffixAutomaton.md new file mode 100644 index 0000000..a5515de --- /dev/null +++ b/content/docs/Strings/suffixAutomaton.md @@ -0,0 +1,83 @@ +--- +weight: 10 +title: "Suffix Automaton" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + Automato que aceita os sufixos de uma string + + Todas as funcoes sao lineares + + + +Link original: [suffixAutomaton.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Strings/suffixAutomaton.cpp) + +## Código +```cpp +namespace sam { + int cur, sz, len[2*MAX], link[2*MAX], acc[2*MAX]; + int nxt[2*MAX][26]; + + void add(int c) { + int at = cur; + len[sz] = len[cur]+1, cur = sz++; + while (at != -1 and !nxt[at][c]) nxt[at][c] = cur, at = link[at]; + if (at == -1) { link[cur] = 0; return; } + int q = nxt[at][c]; + if (len[q] == len[at]+1) { link[cur] = q; return; } + int qq = sz++; + len[qq] = len[at]+1, link[qq] = link[q]; + for (int i = 0; i < 26; i++) nxt[qq][i] = nxt[q][i]; + while (at != -1 and nxt[at][c] == q) nxt[at][c] = qq, at = link[at]; + link[cur] = link[q] = qq; + } + void build(string& s) { + cur = 0, sz = 0, len[0] = 0, link[0] = -1, sz++; + for (auto i : s) add(i-'a'); + int at = cur; + while (at) acc[at] = 1, at = link[at]; + } + + // coisas que da pra fazer: + ll distinct_substrings() { + ll ans = 0; + for (int i = 1; i < sz; i++) ans += len[i] - len[link[i]]; + return ans; + } + string longest_common_substring(string& S, string& T) { + build(S); + int at = 0, l = 0, ans = 0, pos = -1; + for (int i = 0; i < T.size(); i++) { + while (at and !nxt[at][T[i]-'a']) at = link[at], l = len[at]; + if (nxt[at][T[i]-'a']) at = nxt[at][T[i]-'a'], l++; + else at = 0, l = 0; + if (l > ans) ans = l, pos = i; + } + return T.substr(pos-ans+1, ans); + } + ll dp[2*MAX]; + ll paths(int i) { + auto& x = dp[i]; + if (x) return x; + x = 1; + for (int j = 0; j < 26; j++) if (nxt[i][j]) x += paths(nxt[i][j]); + return x; + } + void kth_substring(int k, int at=0) { // k=1 : menor substring lexicog. + for (int i = 0; i < 26; i++) if (k and nxt[at][i]) { + if (paths(nxt[at][i]) >= k) { + cout << char('a'+i); + kth_substring(k-1, nxt[at][i]); + return; + } + k -= paths(nxt[at][i]); + } + } +}; + +``` diff --git a/content/docs/Strings/trie.md b/content/docs/Strings/trie.md new file mode 100644 index 0000000..ee0e38f --- /dev/null +++ b/content/docs/Strings/trie.md @@ -0,0 +1,75 @@ +--- +weight: 10 +title: "Trie" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + trie T() constroi uma trie para o alfabeto das letras minusculas + + trie T(tamanho do alfabeto, menor caracter) tambem pode ser usado + + + + T.insert(s) - O(|s|*sigma) + + T.erase(s) - O(|s|) + + T.find(s) retorna a posicao, -1 se nao achar - O(|s|) + + T.count_pref(s) numero de strings que possuem s como prefixo - O(|s|) + + + +Link original: [trie.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Strings/trie.cpp) + +## Código +```cpp +struct trie { + vector> to; + vector end, pref; + int sigma; char norm; + trie(int sigma_=26, char norm_='a') : sigma(sigma_), norm(norm_) { + to = {vector(sigma)}; + end = {0}, pref = {0}; + } + void insert(string s) { + int x = 0; + for (auto c : s) { + int &nxt = to[x][c-norm]; + if (!nxt) { + nxt = to.size(); + to.push_back(vector(sigma)); + end.push_back(0), pref.push_back(0); + } + x = nxt, pref[x]++; + } + end[x]++, pref[0]++; + } + void erase(string s) { + int x = 0; + for (char c : s) { + int &nxt = to[x][c-norm]; + x = nxt, pref[x]--; + if (!pref[x]) nxt = 0; + } + end[x]--, pref[0]--; + } + int find(string s) { + int x = 0; + for (auto c : s) { + x = to[x][c-norm]; + if (!x) return -1; + } + return x; + } + int count_pref(string s) { + int id = find(s); + return id >= 0 ? pref[id] : 0; + } +}; +``` diff --git a/content/docs/Strings/z.md b/content/docs/Strings/z.md new file mode 100644 index 0000000..5f3b5be --- /dev/null +++ b/content/docs/Strings/z.md @@ -0,0 +1,41 @@ +--- +weight: 10 +title: "Z" +draft: false +toc: true +date: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T17:19:25-0300" +description: "" +--- + +## Sobre + z[i] = lcp(s, s[i..n)) + + + + Complexidades: + + z - O(|s|) + + match - O(|s| + |p|) + + + +Link original: [z.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Strings/z.cpp) + +## Código +```cpp +vector get_z(string s) { + int n = s.size(); + vector z(n, 0); + + int l = 0, r = 0; + for (int i = 1; i < n; i++) { + if (i <= r) z[i] = min(r - i + 1, z[i - l]); + while (i + z[i] < n and s[z[i]] == s[i + z[i]]) z[i]++; + if (i + z[i] - 1 > r) l = i, r = i + z[i] - 1; + } + + return z; +} +``` From e4b4e1e8f6b0ff0c3f02cc3ea04a4d4e36e3214b Mon Sep 17 00:00:00 2001 From: luizacbcampos Date: Thu, 9 May 2024 18:32:29 -0300 Subject: [PATCH 40/43] update docs generation script --- docs/gendocs.cpp | 135 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 125 insertions(+), 10 deletions(-) diff --git a/docs/gendocs.cpp b/docs/gendocs.cpp index dd1bcd2..13a9883 100644 --- a/docs/gendocs.cpp +++ b/docs/gendocs.cpp @@ -7,6 +7,7 @@ using namespace std; #define RED "\033[0;31m" #define RESET "\033[0m" #define CYAN "\033[0;36m" +#define GREEN "\033[0;32m" #define BOLD "\033[1m" #define NO_BOLD "\033[0m" @@ -30,6 +31,7 @@ string hash_cmd = "sed -n 1','10000' p' tmp.cpp | sed '/^#w/d' " bool print_all = false; bool overwrite = false; +bool update = false; void strip(string& str) { if (str.length() == 0) return; @@ -197,6 +199,90 @@ string get_original_link(string path_code) { return link + path_code; } +pair get_code_range(string path_docs) { + ifstream in(path_docs); + string line; + vector lines; + pair code_range; + // Read all lines + while (getline(in, line)) { + lines.push_back(line); + } + in.close(); + + // If line[i] == "##Código", and line[i+1] == "```cpp", then read all lines until line[i] == "```" + for (int i = 0; i < lines.size(); i++) { + if (lines[i] == "## Código" and lines[i + 1] == "```cpp") { + code_range.first = i + 1; + while (i < lines.size() and lines[i] != "```") i++; + code_range.second = i; + break; + } + } + + return code_range; +} + +pair find_dashed_lines(vector& lines) { + pair dashed_lines; + bool found_first_dashed_line = false; + for (int i = 0; i < lines.size(); i++) { + if (lines[i].size() == 3 and lines[i][0] == '-' and lines[i][1] == '-' and lines[i][2] == '-') { + if (!found_first_dashed_line) { + dashed_lines.first = i; + found_first_dashed_line = true; + } + else { + dashed_lines.second = i; + break; + } + } + } + return dashed_lines; +} + +void update_existing_file(string path_docs, string path_code, string title) { + // Updates the code portion of the file + // pair < comments, code > + pair, vector> code = get_code(path_code); + + // Get the range of the code portion + pair code_range = get_code_range(path_docs); + + string line; + vector old_lines; + // Read the file as it is now + ifstream in(path_docs); + while (getline(in, line)) + old_lines.push_back(line); + in.close(); + + pair dashed_lines = find_dashed_lines(old_lines); + + // Update the date portion in the dash lines + for (int i = dashed_lines.first; i < dashed_lines.second; i++) { + if (old_lines[i].rfind("date: \"", 0) == 0) { + old_lines[i] = "date: \"" + time_to_string(get_current_time()) + "\""; // Update the date + } + } + + // Update the code portion + ofstream out(path_docs); + for (int i = 0; i < dashed_lines.first; i++) out << old_lines[i] << endl; // Write everything before the dashed lines + + for (int i = dashed_lines.first; i < dashed_lines.second; i++) out << old_lines[i] << endl; // Write the dashed lines + + for (int i = dashed_lines.second; i < code_range.first; i++) out << old_lines[i] << endl; // Write everything between the dashed lines and the code portion + + out << "```cpp" << endl; // Start of the code portion + for (auto line : code.second) out << line << endl; // Write the new code + out << "```" << endl; + + for (int i = code_range.second + 1; i < old_lines.size(); i++) out << old_lines[i] << endl; // Write everything after the code portion + out.close(); + +} + void create_code_file(string path_docs, string path_code, string title) { // pair < comments, code > pair, vector> code = get_code(path_code); @@ -249,9 +335,10 @@ void create_default_index(string path_index, string index_title) { out.close(); } -void create_section(string path) { +void create_section(string path, string dir = docs_path) { // Check if directory exists - string dir = docs_path + path; + dir += path; + if (fs::is_directory(fs::path(dir))){ // Check if dir + '/_index.md' exists string index = dir + "/_index.md"; @@ -269,6 +356,19 @@ void create_section(string path) { } } +void create_directory(string path_docs) { + const fs::path shorten(path_docs); + fs::path directory = shorten.parent_path(); + + while (!directory.empty()) { + if (!fs::exists(directory)) { + // std::cerr << "Directory " << directory.string() << " does not exist." << std::endl; + create_section(directory.string(), ""); + } + directory = directory.parent_path(); + } +} + int main(int argc, char** argv) { if (argc > 1) { string arg1(argv[1]); @@ -276,6 +376,10 @@ int main(int argc, char** argv) { overwrite = true; cerr << "Rewriting all docs files..." << endl << endl; } + else if (arg1 == "--update") { + update = true; + cerr << "Updating all docs files..." << endl << endl; + } } struct dirent* entry = nullptr; @@ -295,28 +399,39 @@ int main(int argc, char** argv) { // print all files for (auto [f, f_path] : files) { + // const fs::path path = inputPath; string title = get_name(f_path); strip(title); string path_docs = get_docs_path(f_path); cout << CYAN << "\t" << title << RESET << endl; - cerr << "\t" << f_path << " -> " << path_docs << endl; + + create_directory(path_docs); + + if (overwrite) { create_code_file(path_docs, f_path, title); + cerr << "\t" << f_path << " -> " << path_docs << endl; + continue; } - else{ - if (!fs::exists(fs::path(path_docs))) { - create_code_file(path_docs, f_path, title); - } - else { - cerr << "File already exists: " << path_docs << endl; + + if (!fs::exists(fs::path(path_docs))) { + create_code_file(path_docs, f_path, title); + cerr << "\t" << f_path << " -> " << path_docs << endl; + } + else { + if (update) { + update_existing_file(path_docs, f_path, title); + cerr << "\t" << GREEN << "UPDATING: "<< RESET << f_path << " -> " << path_docs << endl; } + else + cerr << "\tFile already exists" << path_docs << endl; } } } // printa_section("Extra"); - vector> files; + // vector> files; // dfs(files, path + "Extra", true); return 0; From 3d812d21c9fb4dc796a1df092248b28b64224df7 Mon Sep 17 00:00:00 2001 From: luizacbcampos Date: Thu, 9 May 2024 18:40:42 -0300 Subject: [PATCH 41/43] fix error in gendocs.cpp --- docs/gendocs.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/gendocs.cpp b/docs/gendocs.cpp index 13a9883..18bcee4 100644 --- a/docs/gendocs.cpp +++ b/docs/gendocs.cpp @@ -362,8 +362,8 @@ void create_directory(string path_docs) { while (!directory.empty()) { if (!fs::exists(directory)) { - // std::cerr << "Directory " << directory.string() << " does not exist." << std::endl; - create_section(directory.string(), ""); + std::cerr << "Directory " << directory.stem().string() << " does not exist." << std::endl; + create_section(directory.stem().string(), directory.parent_path().string()+"/"); } directory = directory.parent_path(); } From 6d7b0fc897d4be432a63978404b7805992c50559 Mon Sep 17 00:00:00 2001 From: luizacbcampos Date: Thu, 9 May 2024 18:41:09 -0300 Subject: [PATCH 42/43] fix folder inside folder mistake --- content/docs/DP/_index.md | 4 +- content/docs/DP/dcDp.md | 4 +- content/docs/DP/lcs.md | 4 +- content/docs/DP/mochila.md | 4 +- content/docs/DP/sosDP.md | 4 +- content/docs/DP/subsetSum.md | 4 +- content/docs/Estruturas/Segtree/_index.md | 8 + content/docs/Estruturas/Segtree/segTreap.md | 139 +++++++++++++++ content/docs/Estruturas/Segtree/segTree.md | 119 +++++++++++++ content/docs/Estruturas/Segtree/segTree2D.md | 83 +++++++++ .../docs/Estruturas/Segtree/segTreeBeats.md | 164 ++++++++++++++++++ .../docs/Estruturas/Segtree/segTreeColor.md | 139 +++++++++++++++ .../docs/Estruturas/Segtree/segTreeEsparsa.md | 75 ++++++++ .../Estruturas/Segtree/segTreeEsparsa2.md | 110 ++++++++++++ .../Estruturas/Segtree/segTreeIterativa.md | 56 ++++++ .../Segtree/segTreeIterativaComLazy.md | 97 +++++++++++ content/docs/Estruturas/Segtree/segTreePa.md | 135 ++++++++++++++ .../Estruturas/Segtree/segTreePersistent.md | 78 +++++++++ .../Segtree/segTreePersistentComLazy.md | 84 +++++++++ content/docs/Estruturas/_index.md | 4 +- content/docs/Estruturas/bit.md | 4 +- content/docs/Estruturas/bit2d.md | 4 +- content/docs/Estruturas/bitRange.md | 4 +- content/docs/Estruturas/bitSortTree.md | 4 +- content/docs/Estruturas/cht.md | 4 +- content/docs/Estruturas/chtDinamico.md | 4 +- content/docs/Estruturas/dsu.md | 4 +- content/docs/Estruturas/lichao.md | 4 +- content/docs/Estruturas/lichaoLazy.md | 4 +- content/docs/Estruturas/mergeSortTree.md | 4 +- content/docs/Estruturas/minqueueDeque.md | 4 +- content/docs/Estruturas/minqueueStack.md | 4 +- content/docs/Estruturas/orderStatisticSet.md | 4 +- content/docs/Estruturas/priorityQueueDs.md | 4 +- content/docs/Estruturas/rangeColor.md | 4 +- content/docs/Estruturas/rmq.md | 4 +- content/docs/Estruturas/slopeTrick.md | 4 +- content/docs/Estruturas/sparseTable.md | 4 +- .../docs/Estruturas/sparseTableDisjunta.md | 4 +- content/docs/Estruturas/splaytree.md | 4 +- content/docs/Estruturas/splaytreeImplicita.md | 4 +- content/docs/Estruturas/splitMergeSet.md | 4 +- content/docs/Estruturas/splitMergeSetLazy.md | 4 +- content/docs/Estruturas/sqrtTree.md | 4 +- content/docs/Estruturas/treap.md | 4 +- content/docs/Estruturas/treapImplicita.md | 4 +- content/docs/Estruturas/treapPersistent.md | 4 +- content/docs/Estruturas/waveletTree.md | 4 +- content/docs/Extra/_index.md | 4 +- content/docs/Grafos/LCA-HLD/_index.md | 8 + content/docs/Grafos/LCA-HLD/hldAresta.md | 91 ++++++++++ content/docs/Grafos/LCA-HLD/hldSemUpdate.md | 64 +++++++ content/docs/Grafos/LCA-HLD/hldVertice.md | 85 +++++++++ content/docs/Grafos/LCA-HLD/lca.md | 90 ++++++++++ .../Grafos/LCA-HLD/lcaComBinaryLifting.md | 116 +++++++++++++ content/docs/Grafos/LCA-HLD/lcaComHld.md | 61 +++++++ content/docs/Grafos/LCT/_index.md | 8 + content/docs/Grafos/LCT/lct.md | 73 ++++++++ content/docs/Grafos/LCT/lctAresta.md | 143 +++++++++++++++ content/docs/Grafos/LCT/lctVertice.md | 133 ++++++++++++++ content/docs/Grafos/_index.md | 4 +- content/docs/Grafos/articulationPoints.md | 4 +- content/docs/Grafos/bellmanFord.md | 4 +- content/docs/Grafos/blockCutTree.md | 4 +- content/docs/Grafos/blossom.md | 4 +- content/docs/Grafos/center.md | 4 +- content/docs/Grafos/centroid.md | 4 +- content/docs/Grafos/centroidDecomp.md | 4 +- content/docs/Grafos/centroidTree.md | 4 +- content/docs/Grafos/cover.md | 4 +- content/docs/Grafos/dijkstra.md | 4 +- content/docs/Grafos/dinitz.md | 4 +- content/docs/Grafos/directedMst.md | 4 +- content/docs/Grafos/dominatorTree.md | 4 +- content/docs/Grafos/eulerPath.md | 4 +- content/docs/Grafos/eulerTourTree.md | 4 +- content/docs/Grafos/floydWarshall.md | 4 +- content/docs/Grafos/functionalGraph.md | 4 +- content/docs/Grafos/hopcroftKarp.md | 4 +- content/docs/Grafos/johnson.md | 4 +- content/docs/Grafos/kosaraju.md | 4 +- content/docs/Grafos/kruskal.md | 4 +- content/docs/Grafos/kuhn.md | 4 +- content/docs/Grafos/linetree.md | 4 +- content/docs/Grafos/lowerBoundMaxFlow.md | 4 +- content/docs/Grafos/minCostMaxFlow.md | 4 +- content/docs/Grafos/prufer.md | 4 +- content/docs/Grafos/sack.md | 4 +- content/docs/Grafos/stableMarriage.md | 4 +- content/docs/Grafos/tarjan.md | 4 +- content/docs/Grafos/topoSort.md | 4 +- content/docs/Grafos/treeIsomorf.md | 4 +- content/docs/Grafos/virtualTree.md | 4 +- content/docs/Matematica/2sat.md | 4 +- content/docs/Matematica/_index.md | 4 +- content/docs/Matematica/berlekampMassey.md | 4 +- content/docs/Matematica/chinese.md | 4 +- content/docs/Matematica/convolution.md | 4 +- content/docs/Matematica/coprimeBasis.md | 4 +- content/docs/Matematica/crivo.md | 4 +- content/docs/Matematica/cycleDetection.md | 4 +- content/docs/Matematica/diofantina.md | 4 +- content/docs/Matematica/divisionTrick.md | 4 +- content/docs/Matematica/evalInterpol.md | 4 +- content/docs/Matematica/fastPow.md | 4 +- content/docs/Matematica/fwht.md | 4 +- content/docs/Matematica/gauss.md | 4 +- content/docs/Matematica/gaussZ2.md | 4 +- content/docs/Matematica/gcdEstendido.md | 4 +- content/docs/Matematica/gcdLcmConvolution.md | 4 +- content/docs/Matematica/integral.md | 4 +- content/docs/Matematica/karatsuba.md | 4 +- content/docs/Matematica/logDiscreto.md | 4 +- content/docs/Matematica/millerRabin.md | 4 +- content/docs/Matematica/modInverse.md | 4 +- content/docs/Matematica/mulmod.md | 4 +- .../docs/Matematica/multipointEvaluation.md | 4 +- content/docs/Matematica/ntt.md | 4 +- content/docs/Matematica/pollardrho.md | 4 +- content/docs/Matematica/powerSeries.md | 4 +- .../docs/Matematica/probabilityBinomial.md | 4 +- content/docs/Matematica/simplex.md | 4 +- content/docs/Matematica/totiente.md | 4 +- content/docs/Primitivas/_index.md | 4 +- content/docs/Primitivas/bigint.md | 4 +- content/docs/Primitivas/calendario.md | 4 +- content/docs/Primitivas/frac.md | 4 +- content/docs/Primitivas/geometria.md | 4 +- content/docs/Primitivas/geometria3d.md | 4 +- content/docs/Primitivas/geometriaInt.md | 4 +- content/docs/Primitivas/matrix.md | 4 +- content/docs/Primitivas/matroid.md | 4 +- content/docs/Primitivas/modularArithmetic.md | 4 +- content/docs/Problemas/_index.md | 4 +- content/docs/Problemas/additionChain.md | 4 +- content/docs/Problemas/angleRange.md | 4 +- content/docs/Problemas/areaHistograma.md | 4 +- content/docs/Problemas/areaUniaoRetangulo.md | 4 +- content/docs/Problemas/binomial.md | 4 +- content/docs/Problemas/closestPairOfPoints.md | 4 +- .../docs/Problemas/conectividadeDinamica.md | 4 +- .../docs/Problemas/conectividadeDinamica2.md | 4 +- content/docs/Problemas/deBrujin.md | 4 +- content/docs/Problemas/delaunay.md | 4 +- content/docs/Problemas/distinct.md | 4 +- content/docs/Problemas/distinctUpdate.md | 4 +- content/docs/Problemas/dominacao3d.md | 4 +- content/docs/Problemas/dominatorPoints.md | 4 +- content/docs/Problemas/dynamicHull.md | 4 +- content/docs/Problemas/graphTriangles.md | 4 +- content/docs/Problemas/grayCode.md | 4 +- .../docs/Problemas/halfPlaneIntersection.md | 4 +- content/docs/Problemas/heapSort.md | 4 +- content/docs/Problemas/hungarian.md | 4 +- .../docs/Problemas/intervalGraphColoring.md | 4 +- content/docs/Problemas/intervalGraphIndSet.md | 4 +- content/docs/Problemas/inversionCount.md | 4 +- content/docs/Problemas/lis.md | 4 +- content/docs/Problemas/lis2.md | 4 +- content/docs/Problemas/maxDist.md | 4 +- content/docs/Problemas/minCirc.md | 4 +- content/docs/Problemas/minkowski.md | 4 +- content/docs/Problemas/mo.md | 4 +- content/docs/Problemas/moDsu.md | 4 +- content/docs/Problemas/moOnTrees.md | 4 +- .../Problemas/palindromicFactorization.md | 4 +- content/docs/Problemas/parsing.md | 4 +- content/docs/Problemas/rmqOffline.md | 4 +- content/docs/Problemas/segmentIntersection.md | 4 +- content/docs/Problemas/simplePolygon.md | 4 +- content/docs/Problemas/steinerTree.md | 4 +- content/docs/Problemas/sweepDirection.md | 4 +- content/docs/Strings/_index.md | 4 +- content/docs/Strings/ahocorasick.md | 4 +- content/docs/Strings/dynamicSuffixArray.md | 4 +- content/docs/Strings/eertree.md | 4 +- content/docs/Strings/hashing.md | 4 +- content/docs/Strings/hashingLargeMod.md | 4 +- content/docs/Strings/kmp.md | 4 +- content/docs/Strings/manacher.md | 4 +- content/docs/Strings/minMaxSuffixCyclic.md | 4 +- content/docs/Strings/suffixArray.md | 4 +- content/docs/Strings/suffixArray2.md | 4 +- content/docs/Strings/suffixAutomaton.md | 4 +- content/docs/Strings/trie.md | 4 +- content/docs/Strings/z.md | 4 +- 186 files changed, 2483 insertions(+), 324 deletions(-) create mode 100644 content/docs/Estruturas/Segtree/_index.md create mode 100644 content/docs/Estruturas/Segtree/segTreap.md create mode 100644 content/docs/Estruturas/Segtree/segTree.md create mode 100644 content/docs/Estruturas/Segtree/segTree2D.md create mode 100644 content/docs/Estruturas/Segtree/segTreeBeats.md create mode 100644 content/docs/Estruturas/Segtree/segTreeColor.md create mode 100644 content/docs/Estruturas/Segtree/segTreeEsparsa.md create mode 100644 content/docs/Estruturas/Segtree/segTreeEsparsa2.md create mode 100644 content/docs/Estruturas/Segtree/segTreeIterativa.md create mode 100644 content/docs/Estruturas/Segtree/segTreeIterativaComLazy.md create mode 100644 content/docs/Estruturas/Segtree/segTreePa.md create mode 100644 content/docs/Estruturas/Segtree/segTreePersistent.md create mode 100644 content/docs/Estruturas/Segtree/segTreePersistentComLazy.md create mode 100644 content/docs/Grafos/LCA-HLD/_index.md create mode 100644 content/docs/Grafos/LCA-HLD/hldAresta.md create mode 100644 content/docs/Grafos/LCA-HLD/hldSemUpdate.md create mode 100644 content/docs/Grafos/LCA-HLD/hldVertice.md create mode 100644 content/docs/Grafos/LCA-HLD/lca.md create mode 100644 content/docs/Grafos/LCA-HLD/lcaComBinaryLifting.md create mode 100644 content/docs/Grafos/LCA-HLD/lcaComHld.md create mode 100644 content/docs/Grafos/LCT/_index.md create mode 100644 content/docs/Grafos/LCT/lct.md create mode 100644 content/docs/Grafos/LCT/lctAresta.md create mode 100644 content/docs/Grafos/LCT/lctVertice.md diff --git a/content/docs/DP/_index.md b/content/docs/DP/_index.md index 5e92923..0087d09 100644 --- a/content/docs/DP/_index.md +++ b/content/docs/DP/_index.md @@ -2,7 +2,7 @@ weight: 10 title: "DP" draft: false -date: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" description: "" -publishdate: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T18:39:19-0300" --- diff --git a/content/docs/DP/dcDp.md b/content/docs/DP/dcDp.md index 5ef3b32..f272cdb 100644 --- a/content/docs/DP/dcDp.md +++ b/content/docs/DP/dcDp.md @@ -3,8 +3,8 @@ weight: 10 title: "Divide and Conquer DP" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/DP/lcs.md b/content/docs/DP/lcs.md index 020590c..0b7857e 100644 --- a/content/docs/DP/lcs.md +++ b/content/docs/DP/lcs.md @@ -3,8 +3,8 @@ weight: 10 title: "Longest Common Subsequence" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/DP/mochila.md b/content/docs/DP/mochila.md index 2fd1cc1..eba26d5 100644 --- a/content/docs/DP/mochila.md +++ b/content/docs/DP/mochila.md @@ -3,8 +3,8 @@ weight: 10 title: "Mochila" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/DP/sosDP.md b/content/docs/DP/sosDP.md index 107bdc8..ee19306 100644 --- a/content/docs/DP/sosDP.md +++ b/content/docs/DP/sosDP.md @@ -3,8 +3,8 @@ weight: 10 title: "SOS DP" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/DP/subsetSum.md b/content/docs/DP/subsetSum.md index 1be883e..67550b1 100644 --- a/content/docs/DP/subsetSum.md +++ b/content/docs/DP/subsetSum.md @@ -3,8 +3,8 @@ weight: 10 title: "Subset sum" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Estruturas/Segtree/_index.md b/content/docs/Estruturas/Segtree/_index.md new file mode 100644 index 0000000..a44cf7d --- /dev/null +++ b/content/docs/Estruturas/Segtree/_index.md @@ -0,0 +1,8 @@ +--- +weight: 10 +title: "Segtree" +draft: false +date: "2024-05-09T18:39:18-0300" +description: "" +publishdate: "2024-05-09T18:39:18-0300" +--- diff --git a/content/docs/Estruturas/Segtree/segTreap.md b/content/docs/Estruturas/Segtree/segTreap.md new file mode 100644 index 0000000..4777354 --- /dev/null +++ b/content/docs/Estruturas/Segtree/segTreap.md @@ -0,0 +1,139 @@ +--- +weight: 10 +title: "SegTreap" +draft: false +toc: true +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" +description: "" +--- + +## Sobre + Muda uma posicao do plano, e faz query de operacao + + associativa e comutativa em retangulo + + Mudar ZERO e op + + Esparso nas duas coordenadas, inicialmente eh tudo ZERO + + + + Para query com distancia de manhattan <= d, faca + + nx = x+y, ny = x-y + + Update em (nx, ny), query em ((nx-d, ny-d), (nx+d, ny+d)) + + + + Valores no X tem que ser de 0 ateh NX + + Para q operacoes, usa O(q log(NX)) de memoria, e as + + operacoes custa O(log(q) log(NX)) + + + +Link original: [segTreap.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Estruturas/Segtree/segTreap.cpp) + +## Código +```cpp +const int ZERO = INF; +const int op(int l, int r) { return min(l, r); } + +mt19937 rng((int) chrono::steady_clock::now().time_since_epoch().count()); + +template struct treap { + struct node { + node *l, *r; + int p; + pair idx; // {y, x} + T val, mi; + node(ll x, ll y, T val_) : l(NULL), r(NULL), p(rng()), + idx(pair(y, x)), val(val_), mi(val) {} + void update() { + mi = val; + if (l) mi = op(mi, l->mi); + if (r) mi = op(mi, r->mi); + } + }; + + node* root; + + treap() { root = NULL; } + ~treap() { + vector q = {root}; + while (q.size()) { + node* x = q.back(); q.pop_back(); + if (!x) continue; + q.push_back(x->l), q.push_back(x->r); + delete x; + } + } + treap(treap&& t) : treap() { swap(root, t.root); } + + void join(node* l, node* r, node*& i) { // assume que l < r + if (!l or !r) return void(i = l ? l : r); + if (l->p > r->p) join(l->r, r, l->r), i = l; + else join(l, r->l, r->l), i = r; + i->update(); + } + void split(node* i, node*& l, node*& r, pair idx) { + if (!i) return void(r = l = NULL); + if (i->idx < idx) split(i->r, i->r, r, idx), l = i; + else split(i->l, l, i->l, idx), r = i; + i->update(); + } + void update(ll x, ll y, T v) { + node *L, *M, *R; + split(root, M, R, pair(y, x+1)), split(M, L, M, pair(y, x)); + if (M) M->val = M->mi = v; + else M = new node(x, y, v); + join(L, M, M), join(M, R, root); + } + T query(ll ly, ll ry) { + node *L, *M, *R; + split(root, M, R, pair(ry, LINF)), split(M, L, M, pair(ly, 0)); + T ret = M ? M->mi : ZERO; + join(L, M, M), join(M, R, root); + return ret; + } +}; + +template struct segtreap { + vector> seg; + vector ch[2]; + ll NX; + + segtreap(ll NX_) : seg(1), NX(NX_) { ch[0].push_back(-1), ch[1].push_back(-1); } + + int get_ch(int i, int d){ + if (ch[d][i] == -1) { + ch[d][i] = seg.size(); + seg.emplace_back(); + ch[0].push_back(-1), ch[1].push_back(-1); + } + return ch[d][i]; + } + + T query(ll lx, ll rx, ll ly, ll ry, int p, ll l, ll r) { + if (rx < l or r < lx) return ZERO; + if (lx <= l and r <= rx) return seg[p].query(ly, ry); + + ll m = l + (r-l)/2; + return op(query(lx, rx, ly, ry, get_ch(p, 0), l, m), + query(lx, rx, ly, ry, get_ch(p, 1), m+1, r)); + } + T query(ll lx, ll rx, ll ly, ll ry) { return query(lx, rx, ly, ry, 0, 0, NX); } + + void update(ll x, ll y, T val, int p, ll l, ll r) { + if (l == r) return seg[p].update(x, y, val); + ll m = l + (r-l)/2; + if (x <= m) update(x, y, val, get_ch(p, 0), l, m); + else update(x, y, val, get_ch(p, 1), m+1, r); + seg[p].update(x, y, val); + } + void update(ll x, ll y, T val) { update(x, y, val, 0, 0, NX); } +}; +``` diff --git a/content/docs/Estruturas/Segtree/segTree.md b/content/docs/Estruturas/Segtree/segTree.md new file mode 100644 index 0000000..f8b0c64 --- /dev/null +++ b/content/docs/Estruturas/Segtree/segTree.md @@ -0,0 +1,119 @@ +--- +weight: 10 +title: "SegTree" +draft: false +toc: true +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" +description: "" +--- + +## Sobre + Recursiva com Lazy Propagation + + Query: soma do range [a, b] + + Update: soma x em cada elemento do range [a, b] + + Pode usar a seguinte funcao para indexar os nohs: + + f(l, r) = (l+r)|(l!=r), usando 2N de memoria + + + + Complexidades: + + build - O(n) + + query - O(log(n)) + + update - O(log(n)) + + + +Link original: [segTree.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Estruturas/Segtree/segTree.cpp) + +## Código +```cpp +namespace seg { + ll seg[4*MAX], lazy[4*MAX]; + int n, *v; + + ll build(int p=1, int l=0, int r=n-1) { + lazy[p] = 0; + if (l == r) return seg[p] = v[l]; + int m = (l+r)/2; + return seg[p] = build(2*p, l, m) + build(2*p+1, m+1, r); + } + void build(int n2, int* v2) { + n = n2, v = v2; + build(); + } + void prop(int p, int l, int r) { + seg[p] += lazy[p]*(r-l+1); + if (l != r) lazy[2*p] += lazy[p], lazy[2*p+1] += lazy[p]; + lazy[p] = 0; + } + ll query(int a, int b, int p=1, int l=0, int r=n-1) { + prop(p, l, r); + if (a <= l and r <= b) return seg[p]; + if (b < l or r < a) return 0; + int m = (l+r)/2; + return query(a, b, 2*p, l, m) + query(a, b, 2*p+1, m+1, r); + } + ll update(int a, int b, int x, int p=1, int l=0, int r=n-1) { + prop(p, l, r); + if (a <= l and r <= b) { + lazy[p] += x; + prop(p, l, r); + return seg[p]; + } + if (b < l or r < a) return seg[p]; + int m = (l+r)/2; + return seg[p] = update(a, b, x, 2*p, l, m) + + update(a, b, x, 2*p+1, m+1, r); + } +}; + + +// Se tiver uma seg de max, da pra descobrir em O(log(n)) +// o primeiro e ultimo elemento >= val numa range: + +// primeira posicao >= val em [a, b] (ou -1 se nao tem) +int get_left(int a, int b, int val, int p=1, int l=0, int r=n-1) { + prop(p, l, r); + if (b < l or r < a or seg[p] < val) return -1; + if (r == l) return l; + int m = (l+r)/2; + int x = get_left(a, b, val, 2*p, l, m); + if (x != -1) return x; + return get_left(a, b, val, 2*p+1, m+1, r); +} + +// ultima posicao >= val em [a, b] (ou -1 se nao tem) +int get_right(int a, int b, int val, int p=1, int l=0, int r=n-1) { + prop(p, l, r); + if (b < l or r < a or seg[p] < val) return -1; + if (r == l) return l; + int m = (l+r)/2; + int x = get_right(a, b, val, 2*p+1, m+1, r); + if (x != -1) return x; + return get_right(a, b, val, 2*p, l, m); +} + +// Se tiver uma seg de soma sobre um array nao negativo v, da pra +// descobrir em O(log(n)) o maior j tal que v[i]+v[i+1]+...+v[j-1] < val +int lower_bound(int i, ll& val, int p, int l, int r) { + prop(p, l, r); + if (r < i) return n; + if (i <= l and seg[p] < val) { + val -= seg[p]; + return n; + } + if (l == r) return l; + int m = (l+r)/2; + int x = lower_bound(i, val, 2*p, l, m); + if (x != n) return x; + return lower_bound(i, val, 2*p+1, m+1, r); +} +``` diff --git a/content/docs/Estruturas/Segtree/segTree2D.md b/content/docs/Estruturas/Segtree/segTree2D.md new file mode 100644 index 0000000..2f8765e --- /dev/null +++ b/content/docs/Estruturas/Segtree/segTree2D.md @@ -0,0 +1,83 @@ +--- +weight: 10 +title: "SegTree 2D Iterativa" +draft: false +toc: true +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" +description: "" +--- + +## Sobre + Consultas 0-based + + Um valor inicial em (x, y) deve ser colocado em seg[x+n][y+n] + + Query: soma do retangulo ((x1, y1), (x2, y2)) + + Update: muda o valor da posicao (x, y) para val + + Nao pergunte como que essa coisa funciona + + + + Para query com distancia de manhattan <= d, faca + + nx = x+y, ny = x-y + + Update em (nx, ny), query em ((nx-d, ny-d), (nx+d, ny+d)) + + + + Se for de min/max, pode tirar os if's da 'query', e fazer + + sempre as 4 operacoes. Fica mais rapido + + + + Complexidades: + + build - O(n^2) + + query - O(log^2(n)) + + update - O(log^2(n)) + + + +Link original: [segTree2D.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Estruturas/Segtree/segTree2D.cpp) + +## Código +```cpp +int seg[2*MAX][2*MAX], n; + +void build() { + for (int x = 2*n; x; x--) for (int y = 2*n; y; y--) { + if (x < n) seg[x][y] = seg[2*x][y] + seg[2*x+1][y]; + if (y < n) seg[x][y] = seg[x][2*y] + seg[x][2*y+1]; + } +} + +int query(int x1, int y1, int x2, int y2) { + int ret = 0, y3 = y1 + n, y4 = y2 + n; + for (x1 += n, x2 += n; x1 <= x2; ++x1 /= 2, --x2 /= 2) + for (y1 = y3, y2 = y4; y1 <= y2; ++y1 /= 2, --y2 /= 2) { + if (x1%2 == 1 and y1%2 == 1) ret += seg[x1][y1]; + if (x1%2 == 1 and y2%2 == 0) ret += seg[x1][y2]; + if (x2%2 == 0 and y1%2 == 1) ret += seg[x2][y1]; + if (x2%2 == 0 and y2%2 == 0) ret += seg[x2][y2]; + } + + return ret; +} + +void update(int x, int y, int val) { + int y2 = y += n; + for (x += n; x; x /= 2, y = y2) { + if (x >= n) seg[x][y] = val; + else seg[x][y] = seg[2*x][y] + seg[2*x+1][y]; + + while (y /= 2) seg[x][y] = seg[x][2*y] + seg[x][2*y+1]; + } +} +``` diff --git a/content/docs/Estruturas/Segtree/segTreeBeats.md b/content/docs/Estruturas/Segtree/segTreeBeats.md new file mode 100644 index 0000000..a9d0b95 --- /dev/null +++ b/content/docs/Estruturas/Segtree/segTreeBeats.md @@ -0,0 +1,164 @@ +--- +weight: 10 +title: "SegTree Beats" +draft: false +toc: true +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" +description: "" +--- + +## Sobre + query(a, b) - {{min(v[a..b]), max(v[a..b])}, sum(v[a..b])} + + updatemin(a, b, x) faz com que v[i] <- min(v[i], x), + + para i em [a, b] + + updatemax faz o mesmo com max, e updatesum soma x + + em todo mundo do intervalo [a, b] + + + + Complexidades: + + build - O(n) + + query - O(log(n)) + + update - O(log^2 (n)) amortizado + + (se nao usar updatesum, fica log(n) amortizado) + + + +Link original: [segTreeBeats.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Estruturas/Segtree/segTreeBeats.cpp) + +## Código +```cpp +#define f first +#define s second + +namespace beats { + struct node { + int tam; + ll sum, lazy; // lazy pra soma + ll mi1, mi2, mi; // mi = #mi1 + ll ma1, ma2, ma; // ma = #ma1 + + node(ll x = 0) { + sum = mi1 = ma1 = x; + mi2 = LINF, ma2 = -LINF; + mi = ma = tam = 1; + lazy = 0; + } + node(const node& l, const node& r) { + sum = l.sum + r.sum, tam = l.tam + r.tam; + lazy = 0; + if (l.mi1 > r.mi1) { + mi1 = r.mi1, mi = r.mi; + mi2 = min(l.mi1, r.mi2); + } else if (l.mi1 < r.mi1) { + mi1 = l.mi1, mi = l.mi; + mi2 = min(r.mi1, l.mi2); + } else { + mi1 = l.mi1, mi = l.mi+r.mi; + mi2 = min(l.mi2, r.mi2); + } + if (l.ma1 < r.ma1) { + ma1 = r.ma1, ma = r.ma; + ma2 = max(l.ma1, r.ma2); + } else if (l.ma1 > r.ma1) { + ma1 = l.ma1, ma = l.ma; + ma2 = max(r.ma1, l.ma2); + } else { + ma1 = l.ma1, ma = l.ma+r.ma; + ma2 = max(l.ma2, r.ma2); + } + } + void setmin(ll x) { + if (x >= ma1) return; + sum += (x - ma1)*ma; + if (mi1 == ma1) mi1 = x; + if (mi2 == ma1) mi2 = x; + ma1 = x; + } + void setmax(ll x) { + if (x <= mi1) return; + sum += (x - mi1)*mi; + if (ma1 == mi1) ma1 = x; + if (ma2 == mi1) ma2 = x; + mi1 = x; + } + void setsum(ll x) { + mi1 += x, mi2 += x, ma1 += x, ma2 += x; + sum += x*tam; + lazy += x; + } + }; + + node seg[4*MAX]; + int n, *v; + + node build(int p=1, int l=0, int r=n-1) { + if (l == r) return seg[p] = {v[l]}; + int m = (l+r)/2; + return seg[p] = {build(2*p, l, m), build(2*p+1, m+1, r)}; + } + void build(int n2, int* v2) { + n = n2, v = v2; + build(); + } + void prop(int p, int l, int r) { + if (l == r) return; + for (int k = 0; k < 2; k++) { + if (seg[p].lazy) seg[2*p+k].setsum(seg[p].lazy); + seg[2*p+k].setmin(seg[p].ma1); + seg[2*p+k].setmax(seg[p].mi1); + } + seg[p].lazy = 0; + } + pair, ll> query(int a, int b, int p=1, int l=0, int r=n-1) { + if (b < l or r < a) return {{LINF, -LINF}, 0}; + if (a <= l and r <= b) return {{seg[p].mi1, seg[p].ma1}, seg[p].sum}; + prop(p, l, r); + int m = (l+r)/2; + auto L = query(a, b, 2*p, l, m), R = query(a, b, 2*p+1, m+1, r); + return {{min(L.f.f, R.f.f), max(L.f.s, R.f.s)}, L.s+R.s}; + } + node updatemin(int a, int b, ll x, int p=1, int l=0, int r=n-1) { + if (b < l or r < a or seg[p].ma1 <= x) return seg[p]; + if (a <= l and r <= b and seg[p].ma2 < x) { + seg[p].setmin(x); + return seg[p]; + } + prop(p, l, r); + int m = (l+r)/2; + return seg[p] = {updatemin(a, b, x, 2*p, l, m), + updatemin(a, b, x, 2*p+1, m+1, r)}; + } + node updatemax(int a, int b, ll x, int p=1, int l=0, int r=n-1) { + if (b < l or r < a or seg[p].mi1 >= x) return seg[p]; + if (a <= l and r <= b and seg[p].mi2 > x) { + seg[p].setmax(x); + return seg[p]; + } + prop(p, l, r); + int m = (l+r)/2; + return seg[p] = {updatemax(a, b, x, 2*p, l, m), + updatemax(a, b, x, 2*p+1, m+1, r)}; + } + node updatesum(int a, int b, ll x, int p=1, int l=0, int r=n-1) { + if (b < l or r < a) return seg[p]; + if (a <= l and r <= b) { + seg[p].setsum(x); + return seg[p]; + } + prop(p, l, r); + int m = (l+r)/2; + return seg[p] = {updatesum(a, b, x, 2*p, l, m), + updatesum(a, b, x, 2*p+1, m+1, r)}; + } +}; +``` diff --git a/content/docs/Estruturas/Segtree/segTreeColor.md b/content/docs/Estruturas/Segtree/segTreeColor.md new file mode 100644 index 0000000..5903c92 --- /dev/null +++ b/content/docs/Estruturas/Segtree/segTreeColor.md @@ -0,0 +1,139 @@ +--- +weight: 10 +title: "SegTree Colorida" +draft: false +toc: true +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" +description: "" +--- + +## Sobre + Cada posicao tem um valor e uma cor + + O construtor receve um vector de {valor, cor} + + e o numero de cores (as cores devem estar em [0, c-1]) + + query(c, a, b) retorna a soma dos valores + + de todo mundo em [a, b] que tem cor c + + update(c, a, b, x) soma x em todo mundo em + + [a, b] que tem cor c + + paint(c1, c2, a, b) faz com que todo mundo + + em [a, b] que tem cor c1 passe a ter cor c2 + + + + Complexidades: + + construir - O(n log(n)) espaco e tempo + + query - O(log(n)) + + update - O(log(n)) + + paint - O(log(n)) amortizado + + + +Link original: [segTreeColor.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Estruturas/Segtree/segTreeColor.cpp) + +## Código +```cpp +struct seg_color { + struct node { + node *l, *r; + int cnt; + ll val, lazy; + node() : l(NULL), r(NULL), cnt(0), val(0), lazy(0) {} + void update() { + cnt = 0, val = 0; + for (auto i : {l, r}) if (i) { + i->prop(); + cnt += i->cnt, val += i->val; + } + } + void prop() { + if (!lazy) return; + val += lazy*(ll)cnt; + for (auto i : {l, r}) if (i) i->lazy += lazy; + lazy = 0; + } + }; + + int n; + vector seg; + + seg_color(vector>& v, int c) : n(v.size()), seg(c, NULL) { + for (int i = 0; i < n; i++) + seg[v[i].second] = insert(seg[v[i].second], i, v[i].first, 0, n-1); + } + ~seg_color() { + queue q; + for (auto i : seg) q.push(i); + while (q.size()) { + auto i = q.front(); q.pop(); + if (!i) continue; + q.push(i->l), q.push(i->r); + delete i; + } + } + + node* insert(node* at, int idx, int val, int l, int r) { + if (!at) at = new node(); + if (l == r) return at->cnt = 1, at->val = val, at; + int m = (l+r)/2; + if (idx <= m) at->l = insert(at->l, idx, val, l, m); + else at->r = insert(at->r, idx, val, m+1, r); + return at->update(), at; + } + ll query(node* at, int a, int b, int l, int r) { + if (!at or b < l or r < a) return 0; + at->prop(); + if (a <= l and r <= b) return at->val; + int m = (l+r)/2; + return query(at->l, a, b, l, m) + query(at->r, a, b, m+1, r); + } + ll query(int c, int a, int b) { return query(seg[c], a, b, 0, n-1); } + void update(node* at, int a, int b, int x, int l, int r) { + if (!at or b < l or r < a) return; + at->prop(); + if (a <= l and r <= b) { + at->lazy += x; + return void(at->prop()); + } + int m = (l+r)/2; + update(at->l, a, b, x, l, m), update(at->r, a, b, x, m+1, r); + at->update(); + } + void update(int c, int a, int b, int x) { update(seg[c], a, b, x, 0, n-1); } + void paint(node*& from, node*& to, int a, int b, int l, int r) { + if (to == from or !from or b < l or r < a) return; + from->prop(); + if (to) to->prop(); + if (a <= l and r <= b) { + if (!to) { + to = from; + from = NULL; + return; + } + int m = (l+r)/2; + paint(from->l, to->l, a, b, l, m), paint(from->r, to->r, a, b, m+1, r); + to->update(); + delete from; + from = NULL; + return; + } + if (!to) to = new node(); + int m = (l+r)/2; + paint(from->l, to->l, a, b, l, m), paint(from->r, to->r, a, b, m+1, r); + from->update(), to->update(); + } + void paint(int c1, int c2, int a, int b) { paint(seg[c1], seg[c2], a, b, 0, n-1); } +}; +``` diff --git a/content/docs/Estruturas/Segtree/segTreeEsparsa.md b/content/docs/Estruturas/Segtree/segTreeEsparsa.md new file mode 100644 index 0000000..147e27c --- /dev/null +++ b/content/docs/Estruturas/Segtree/segTreeEsparsa.md @@ -0,0 +1,75 @@ +--- +weight: 10 +title: "SegTree Esparsa - Lazy" +draft: false +toc: true +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" +description: "" +--- + +## Sobre + Query: soma do range [a, b] + + Update: flipa os valores de [a, b] + + O MAX tem q ser Q log N para Q updates + + + + Complexidades: + + build - O(1) + + query - O(log(n)) + + update - O(log(n)) + + + +Link original: [segTreeEsparsa.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Estruturas/Segtree/segTreeEsparsa.cpp) + +## Código +```cpp +namespace seg { + int seg[MAX], lazy[MAX], R[MAX], L[MAX], ptr; + int get_l(int i){ + if (L[i] == 0) L[i] = ptr++; + return L[i]; + } + int get_r(int i){ + if (R[i] == 0) R[i] = ptr++; + return R[i]; + } + + void build() { ptr = 2; } + + void prop(int p, int l, int r) { + if (!lazy[p]) return; + seg[p] = r-l+1 - seg[p]; + if (l != r) lazy[get_l(p)]^=lazy[p], lazy[get_r(p)]^=lazy[p]; + lazy[p] = 0; + } + + int query(int a, int b, int p=1, int l=0, int r=N-1) { + prop(p, l, r); + if (b < l or r < a) return 0; + if (a <= l and r <= b) return seg[p]; + + int m = (l+r)/2; + return query(a, b, get_l(p), l, m)+query(a, b, get_r(p), m+1, r); + } + + int update(int a, int b, int p=1, int l=0, int r=N-1) { + prop(p, l, r); + if (b < l or r < a) return seg[p]; + if (a <= l and r <= b) { + lazy[p] ^= 1; + prop(p, l, r); + return seg[p]; + } + int m = (l+r)/2; + return seg[p] = update(a, b, get_l(p), l, m)+update(a, b, get_r(p), m+1, r); + } +}; +``` diff --git a/content/docs/Estruturas/Segtree/segTreeEsparsa2.md b/content/docs/Estruturas/Segtree/segTreeEsparsa2.md new file mode 100644 index 0000000..e2326b5 --- /dev/null +++ b/content/docs/Estruturas/Segtree/segTreeEsparsa2.md @@ -0,0 +1,110 @@ +--- +weight: 10 +title: "SegTree Esparsa - O(q) memoria" +draft: false +toc: true +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" +description: "" +--- + +## Sobre + Query: min do range [a, b] + + Update: troca o valor de uma posicao + + Usa O(q) de memoria para q updates + + + + Complexidades: + + query - O(log(n)) + + update - O(log(n)) + + + +Link original: [segTreeEsparsa2.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Estruturas/Segtree/segTreeEsparsa2.cpp) + +## Código +```cpp +template struct seg { + struct node { + node* ch[2]; + char d; + T v; + + T mi; + + node(int d_, T v_, T val) : d(d_), v(v_) { + ch[0] = ch[1] = NULL; + mi = val; + } + node(node* x) : d(x->d), v(x->v), mi(x->mi) { + ch[0] = x->ch[0], ch[1] = x->ch[1]; + } + void update() { + mi = numeric_limits::max(); + for (int i = 0; i < 2; i++) if (ch[i]) + mi = min(mi, ch[i]->mi); + } + }; + + node* root; + char n; + + seg() : root(NULL), n(0) {} + ~seg() { + std::vector q = {root}; + while (q.size()) { + node* x = q.back(); q.pop_back(); + if (!x) continue; + q.push_back(x->ch[0]), q.push_back(x->ch[1]); + delete x; + } + } + + char msb(T v, char l, char r) { // msb in range (l, r] + for (char i = r; i > l; i--) if (v>>i&1) return i; + return -1; + } + void cut(node* at, T v, char i) { + char d = msb(v ^ at->v, at->d, i); + if (d == -1) return; // no need to split + node* nxt = new node(at); + at->ch[v>>d&1] = NULL; + at->ch[!(v>>d&1)] = nxt; + at->d = d; + } + + node* update(node* at, T idx, T val, char i) { + if (!at) return new node(-1, idx, val); + cut(at, idx, i); + if (at->d == -1) { // leaf + at->mi = val; + return at; + } + bool dir = idx>>at->d&1; + at->ch[dir] = update(at->ch[dir], idx, val, at->d-1); + at->update(); + return at; + } + void update(T idx, T val) { + while (idx>>n) n++; + root = update(root, idx, val, n-1); + } + + T query(node* at, T a, T b, T l, T r, char i) { + if (!at or b < l or r < a) return numeric_limits::max(); + if (a <= l and r <= b) return at->mi; + T m = l + (r-l)/2; + if (at->d < i) { + if ((at->v>>i&1) == 0) return query(at, a, b, l, m, i-1); + else return query(at, a, b, m+1, r, i-1); + } + return min(query(at->ch[0], a, b, l, m, i-1), query(at->ch[1], a, b, m+1, r, i-1)); + } + T query(T l, T r) { return query(root, l, r, 0, (T(1)<> s; + if (lazy[i]) { + poe(2*i, lazy[i], tam); + poe(2*i+1, lazy[i], tam); + lazy[i] = 0; + } + } + } + + void build(int n2, int* v) { + n = n2; + for (int i = 0; i < n; i++) seg[n+i] = v[i]; + for (int i = n-1; i; i--) seg[i] = junta(seg[2*i], seg[2*i+1]); + for (int i = 0; i < 2*n; i++) lazy[i] = 0; + } + + ll query(int a, int b) { + ll ret = 0; + for (prop(a+=n), prop(b+=n); a <= b; ++a/=2, --b/=2) { + if (a%2 == 1) ret = junta(ret, seg[a]); + if (b%2 == 0) ret = junta(ret, seg[b]); + } + return ret; + } + + void update(int a, int b, int x) { + int a2 = a += n, b2 = b += n, tam = 1; + for (; a <= b; ++a/=2, --b/=2, tam *= 2) { + if (a%2 == 1) poe(a, x, tam); + if (b%2 == 0) poe(b, x, tam); + } + sobe(a2), sobe(b2); + } +}; + +``` diff --git a/content/docs/Estruturas/Segtree/segTreePa.md b/content/docs/Estruturas/Segtree/segTreePa.md new file mode 100644 index 0000000..755e57f --- /dev/null +++ b/content/docs/Estruturas/Segtree/segTreePa.md @@ -0,0 +1,135 @@ +--- +weight: 10 +title: "SegTree PA" +draft: false +toc: true +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" +description: "" +--- + +## Sobre + Segtree de PA + + update_set(l, r, A, R) seta [l, r] para PA(A, R), + + update_add soma PA(A, R) em [l, r] + + query(l, r) retorna a soma de [l, r] + + + + PA(A, R) eh a PA: [A+R, A+2R, A+3R, ... ] + + + + Complexidades: + + construir - O(n) + + update_set, update_add, query - O(log(n)) + + + +Link original: [segTreePa.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Estruturas/Segtree/segTreePa.cpp) + +## Código +```cpp +struct seg_pa { + struct Data { + ll sum; + ll set_a, set_r, add_a, add_r; + Data() : sum(0), set_a(LINF), set_r(0), add_a(0), add_r(0) {} + }; + vector seg; + int n; + + seg_pa(int n_) { + n = n_; + seg = vector(4*n); + } + + void prop(int p, int l, int r) { + int tam = r-l+1; + ll &sum = seg[p].sum, &set_a = seg[p].set_a, &set_r = seg[p].set_r, + &add_a = seg[p].add_a, &add_r = seg[p].add_r; + + if (set_a != LINF) { + set_a += add_a, set_r += add_r; + sum = set_a*tam + set_r*tam*(tam+1)/2; + if (l != r) { + int m = (l+r)/2; + + seg[2*p].set_a = set_a; + seg[2*p].set_r = set_r; + seg[2*p].add_a = seg[2*p].add_r = 0; + + seg[2*p+1].set_a = set_a + set_r * (m-l+1); + seg[2*p+1].set_r = set_r; + seg[2*p+1].add_a = seg[2*p+1].add_r = 0; + } + set_a = LINF, set_r = 0; + add_a = add_r = 0; + } else if (add_a or add_r) { + sum += add_a*tam + add_r*tam*(tam+1)/2; + if (l != r) { + int m = (l+r)/2; + + seg[2*p].add_a += add_a; + seg[2*p].add_r += add_r; + + seg[2*p+1].add_a += add_a + add_r * (m-l+1); + seg[2*p+1].add_r += add_r; + } + add_a = add_r = 0; + } + } + + int inter(pair a, pair b) { + if (a.first > b.first) swap(a, b); + return max(0, min(a.second, b.second) - b.first + 1); + } + ll set(int a, int b, ll aa, ll rr, int p, int l, int r) { + prop(p, l, r); + if (b < l or r < a) return seg[p].sum; + if (a <= l and r <= b) { + seg[p].set_a = aa; + seg[p].set_r = rr; + prop(p, l, r); + return seg[p].sum; + } + int m = (l+r)/2; + int tam_l = inter({l, m}, {a, b}); + return seg[p].sum = set(a, b, aa, rr, 2*p, l, m) + + set(a, b, aa + rr * tam_l, rr, 2*p+1, m+1, r); + } + void update_set(int l, int r, ll aa, ll rr) { + set(l, r, aa, rr, 1, 0, n-1); + } + ll add(int a, int b, ll aa, ll rr, int p, int l, int r) { + prop(p, l, r); + if (b < l or r < a) return seg[p].sum; + if (a <= l and r <= b) { + seg[p].add_a += aa; + seg[p].add_r += rr; + prop(p, l, r); + return seg[p].sum; + } + int m = (l+r)/2; + int tam_l = inter({l, m}, {a, b}); + return seg[p].sum = add(a, b, aa, rr, 2*p, l, m) + + add(a, b, aa + rr * tam_l, rr, 2*p+1, m+1, r); + } + void update_add(int l, int r, ll aa, ll rr) { + add(l, r, aa, rr, 1, 0, n-1); + } + ll query(int a, int b, int p, int l, int r) { + prop(p, l, r); + if (b < l or r < a) return 0; + if (a <= l and r <= b) return seg[p].sum; + int m = (l+r)/2; + return query(a, b, 2*p, l, m) + query(a, b, 2*p+1, m+1, r); + } + ll query(int l, int r) { return query(l, r, 1, 0, n-1); } +}; +``` diff --git a/content/docs/Estruturas/Segtree/segTreePersistent.md b/content/docs/Estruturas/Segtree/segTreePersistent.md new file mode 100644 index 0000000..cdcf84b --- /dev/null +++ b/content/docs/Estruturas/Segtree/segTreePersistent.md @@ -0,0 +1,78 @@ +--- +weight: 10 +title: "SegTree Persistente" +draft: false +toc: true +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" +description: "" +--- + +## Sobre + SegTree de soma, update de somar numa posicao + + + + query(a, b, t) retorna a query de [a, b] na versao t + + update(a, x, t) faz um update v[a]+=x a partir da + + versao de t, criando uma nova versao e retornando seu id + + Por default, faz o update a partir da ultima versao + + + + build - O(n) + + query - O(log(n)) + + update - O(log(n)) + + + +Link original: [segTreePersistent.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Estruturas/Segtree/segTreePersistent.cpp) + +## Código +```cpp +const int MAX = 1e5+10, UPD = 1e5+10, LOG = 18; +const int MAXS = 2*MAX+UPD*LOG; + +namespace perseg { + ll seg[MAXS]; + int rt[UPD], L[MAXS], R[MAXS], cnt, t; + int n, *v; + + ll build(int p, int l, int r) { + if (l == r) return seg[p] = v[l]; + L[p] = cnt++, R[p] = cnt++; + int m = (l+r)/2; + return seg[p] = build(L[p], l, m) + build(R[p], m+1, r); + } + void build(int n2, int* v2) { + n = n2, v = v2; + rt[0] = cnt++; + build(0, 0, n-1); + } + ll query(int a, int b, int p, int l, int r) { + if (b < l or r < a) return 0; + if (a <= l and r <= b) return seg[p]; + int m = (l+r)/2; + return query(a, b, L[p], l, m) + query(a, b, R[p], m+1, r); + } + ll query(int a, int b, int tt) { + return query(a, b, rt[tt], 0, n-1); + } + ll update(int a, int x, int lp, int p, int l, int r) { + if (l == r) return seg[p] = seg[lp]+x; + int m = (l+r)/2; + if (a <= m) + return seg[p] = update(a, x, L[lp], L[p]=cnt++, l, m) + seg[R[p]=R[lp]]; + return seg[p] = seg[L[p]=L[lp]] + update(a, x, R[lp], R[p]=cnt++, m+1, r); + } + int update(int a, int x, int tt=t) { + update(a, x, rt[tt], rt[++t]=cnt++, 0, n-1); + return t; + } +}; +``` diff --git a/content/docs/Estruturas/Segtree/segTreePersistentComLazy.md b/content/docs/Estruturas/Segtree/segTreePersistentComLazy.md new file mode 100644 index 0000000..46b1764 --- /dev/null +++ b/content/docs/Estruturas/Segtree/segTreePersistentComLazy.md @@ -0,0 +1,84 @@ +--- +weight: 10 +title: "SegTree Persistente com Lazy" +draft: false +toc: true +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" +description: "" +--- + +## Sobre + Nao propaga, meio estranho de mexer, mas da + + + + query(a, b, t) retorna a query de [a, b] na versao t + + update(a, b, x, t) faz um update v[a..b]+=x a partir da + + versao de t, criando uma nova versao e retornando seu id + + Por default, faz o update a partir da ultima versao + + + + build - O(n) + + query - O(log(n)) + + update - O(log(n)) + + + +Link original: [segTreePersistentComLazy.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Estruturas/Segtree/segTreePersistentComLazy.cpp) + +## Código +```cpp +const int MAX = 1e5+10, UPD = 1e5+10, LOG = 18; +const int MAXS = 2*MAX + 4*UPD*LOG; + +namespace perseg { + int seg[MAXS]; + int rt[UPD], L[MAXS], R[MAXS], cnt, t; + int n, *v; + + int build(int p, int l, int r) { + if (l == r) return seg[p] = v[l]; + L[p] = cnt++, R[p] = cnt++; + int m = (l+r)/2; + return seg[p] = max(build(L[p], l, m), build(R[p], m+1, r)); + } + void build(int n2, int *v2) { + n = n2, v = v2; + rt[0] = cnt++; + build(0, 0, n-1); + } + int query(int a, int b, int p, int l, int r) { + if (b < l or r < a) return -INF; + if (a <= l and r <= b) return lazy[p] + seg[p]; + int m = (l+r)/2; + int ret = lazy[p] + max(query(a, b, L[p], l, m), query(a, b, R[p], m+1, r)); + return ret; + } + int query(int a, int b, int tt) { + return query(a, b, rt[tt], 0, n-1); + } + int update(int a, int b, int x, int lp, int p, int l, int r) { + tie(seg[p], lazy[p], L[p], R[p]) = {seg[lp], lazy[lp], L[lp], R[lp]}; + if (b < l or r < a) return seg[p] + lazy[p]; + if (a <= l and r <= b) return seg[p] + (lazy[p] += x); + + int m = (l+r)/2; + seg[p] = max(update(a, b, x, L[lp], L[p] = cnt++, l, m), + update(a, b, x, R[lp], R[p] = cnt++, m+1, r)); + lazy[p] = lazy[lp]; + return seg[p] + lazy[p]; + } + int update(int a, int b, int x, int tt=t) { + assert(tt <= t); + update(a, b, x, rt[tt], rt[++t]=cnt++, 0, n-1); + return t; + } +}; +``` diff --git a/content/docs/Estruturas/_index.md b/content/docs/Estruturas/_index.md index 7da7f37..9e4e409 100644 --- a/content/docs/Estruturas/_index.md +++ b/content/docs/Estruturas/_index.md @@ -2,7 +2,7 @@ weight: 10 title: "Estruturas" draft: false -date: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" description: "" -publishdate: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T18:39:18-0300" --- diff --git a/content/docs/Estruturas/bit.md b/content/docs/Estruturas/bit.md index 4f636be..4f62be8 100644 --- a/content/docs/Estruturas/bit.md +++ b/content/docs/Estruturas/bit.md @@ -3,8 +3,8 @@ weight: 10 title: "BIT" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Estruturas/bit2d.md b/content/docs/Estruturas/bit2d.md index 89dded3..17fe08c 100644 --- a/content/docs/Estruturas/bit2d.md +++ b/content/docs/Estruturas/bit2d.md @@ -3,8 +3,8 @@ weight: 10 title: "BIT 2D" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Estruturas/bitRange.md b/content/docs/Estruturas/bitRange.md index b862129..7e4ce98 100644 --- a/content/docs/Estruturas/bitRange.md +++ b/content/docs/Estruturas/bitRange.md @@ -3,8 +3,8 @@ weight: 10 title: "BIT com update em range" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Estruturas/bitSortTree.md b/content/docs/Estruturas/bitSortTree.md index 4a21198..d4907c6 100644 --- a/content/docs/Estruturas/bitSortTree.md +++ b/content/docs/Estruturas/bitSortTree.md @@ -3,8 +3,8 @@ weight: 10 title: "BIT-Sort Tree" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Estruturas/cht.md b/content/docs/Estruturas/cht.md index 3caafaf..72c13ff 100644 --- a/content/docs/Estruturas/cht.md +++ b/content/docs/Estruturas/cht.md @@ -3,8 +3,8 @@ weight: 10 title: "Convex Hull Trick Estatico" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Estruturas/chtDinamico.md b/content/docs/Estruturas/chtDinamico.md index cea145e..3e96558 100644 --- a/content/docs/Estruturas/chtDinamico.md +++ b/content/docs/Estruturas/chtDinamico.md @@ -3,8 +3,8 @@ weight: 10 title: "Convex Hull Trick Dinamico" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Estruturas/dsu.md b/content/docs/Estruturas/dsu.md index eb955a6..679b098 100644 --- a/content/docs/Estruturas/dsu.md +++ b/content/docs/Estruturas/dsu.md @@ -3,8 +3,8 @@ weight: 10 title: "DSU" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Estruturas/lichao.md b/content/docs/Estruturas/lichao.md index 5d0f42c..73e698d 100644 --- a/content/docs/Estruturas/lichao.md +++ b/content/docs/Estruturas/lichao.md @@ -3,8 +3,8 @@ weight: 10 title: "Li-Chao Tree" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Estruturas/lichaoLazy.md b/content/docs/Estruturas/lichaoLazy.md index c5d40e0..115d196 100644 --- a/content/docs/Estruturas/lichaoLazy.md +++ b/content/docs/Estruturas/lichaoLazy.md @@ -3,8 +3,8 @@ weight: 10 title: "Li-Chao Tree - Lazy" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Estruturas/mergeSortTree.md b/content/docs/Estruturas/mergeSortTree.md index cc73002..c580147 100644 --- a/content/docs/Estruturas/mergeSortTree.md +++ b/content/docs/Estruturas/mergeSortTree.md @@ -3,8 +3,8 @@ weight: 10 title: "MergeSort Tree" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Estruturas/minqueueDeque.md b/content/docs/Estruturas/minqueueDeque.md index fff8226..9ce584e 100644 --- a/content/docs/Estruturas/minqueueDeque.md +++ b/content/docs/Estruturas/minqueueDeque.md @@ -3,8 +3,8 @@ weight: 10 title: "Min queue - deque" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Estruturas/minqueueStack.md b/content/docs/Estruturas/minqueueStack.md index 29d9f25..b617eba 100644 --- a/content/docs/Estruturas/minqueueStack.md +++ b/content/docs/Estruturas/minqueueStack.md @@ -3,8 +3,8 @@ weight: 10 title: "Min queue - stack" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Estruturas/orderStatisticSet.md b/content/docs/Estruturas/orderStatisticSet.md index 38f7e97..4481265 100644 --- a/content/docs/Estruturas/orderStatisticSet.md +++ b/content/docs/Estruturas/orderStatisticSet.md @@ -3,8 +3,8 @@ weight: 10 title: "Order Statistic Set" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Estruturas/priorityQueueDs.md b/content/docs/Estruturas/priorityQueueDs.md index 878b972..90d67d8 100644 --- a/content/docs/Estruturas/priorityQueueDs.md +++ b/content/docs/Estruturas/priorityQueueDs.md @@ -3,8 +3,8 @@ weight: 10 title: "Priority Queue DS" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Estruturas/rangeColor.md b/content/docs/Estruturas/rangeColor.md index 4b2a20b..897146c 100644 --- a/content/docs/Estruturas/rangeColor.md +++ b/content/docs/Estruturas/rangeColor.md @@ -3,8 +3,8 @@ weight: 10 title: "Range color" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Estruturas/rmq.md b/content/docs/Estruturas/rmq.md index f2b57bf..1dc55cf 100644 --- a/content/docs/Estruturas/rmq.md +++ b/content/docs/Estruturas/rmq.md @@ -3,8 +3,8 @@ weight: 10 title: "RMQ - min queue" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Estruturas/slopeTrick.md b/content/docs/Estruturas/slopeTrick.md index 49a2bb4..cd325dd 100644 --- a/content/docs/Estruturas/slopeTrick.md +++ b/content/docs/Estruturas/slopeTrick.md @@ -3,8 +3,8 @@ weight: 10 title: "SlopeTrick" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Estruturas/sparseTable.md b/content/docs/Estruturas/sparseTable.md index 8db92f3..1be04da 100644 --- a/content/docs/Estruturas/sparseTable.md +++ b/content/docs/Estruturas/sparseTable.md @@ -3,8 +3,8 @@ weight: 10 title: "Sparse Table" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Estruturas/sparseTableDisjunta.md b/content/docs/Estruturas/sparseTableDisjunta.md index 80f954e..3519b59 100644 --- a/content/docs/Estruturas/sparseTableDisjunta.md +++ b/content/docs/Estruturas/sparseTableDisjunta.md @@ -3,8 +3,8 @@ weight: 10 title: "Sparse Table Disjunta" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Estruturas/splaytree.md b/content/docs/Estruturas/splaytree.md index 60a08cb..e4c615b 100644 --- a/content/docs/Estruturas/splaytree.md +++ b/content/docs/Estruturas/splaytree.md @@ -3,8 +3,8 @@ weight: 10 title: "Splay Tree" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Estruturas/splaytreeImplicita.md b/content/docs/Estruturas/splaytreeImplicita.md index dcfc037..5433c48 100644 --- a/content/docs/Estruturas/splaytreeImplicita.md +++ b/content/docs/Estruturas/splaytreeImplicita.md @@ -3,8 +3,8 @@ weight: 10 title: "Splay Tree Implicita" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Estruturas/splitMergeSet.md b/content/docs/Estruturas/splitMergeSet.md index 07ca428..6c32311 100644 --- a/content/docs/Estruturas/splitMergeSet.md +++ b/content/docs/Estruturas/splitMergeSet.md @@ -3,8 +3,8 @@ weight: 10 title: "Split-Merge Set" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Estruturas/splitMergeSetLazy.md b/content/docs/Estruturas/splitMergeSetLazy.md index c7762ad..89ed07c 100644 --- a/content/docs/Estruturas/splitMergeSetLazy.md +++ b/content/docs/Estruturas/splitMergeSetLazy.md @@ -3,8 +3,8 @@ weight: 10 title: "Split-Merge Set - Lazy" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Estruturas/sqrtTree.md b/content/docs/Estruturas/sqrtTree.md index 7edf8a6..18daace 100644 --- a/content/docs/Estruturas/sqrtTree.md +++ b/content/docs/Estruturas/sqrtTree.md @@ -3,8 +3,8 @@ weight: 10 title: "SQRT Tree" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Estruturas/treap.md b/content/docs/Estruturas/treap.md index 3965d2f..45169e8 100644 --- a/content/docs/Estruturas/treap.md +++ b/content/docs/Estruturas/treap.md @@ -3,8 +3,8 @@ weight: 10 title: "Treap" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Estruturas/treapImplicita.md b/content/docs/Estruturas/treapImplicita.md index d2af033..3254c90 100644 --- a/content/docs/Estruturas/treapImplicita.md +++ b/content/docs/Estruturas/treapImplicita.md @@ -3,8 +3,8 @@ weight: 10 title: "Treap Implicita" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Estruturas/treapPersistent.md b/content/docs/Estruturas/treapPersistent.md index eca0ccc..7ecf528 100644 --- a/content/docs/Estruturas/treapPersistent.md +++ b/content/docs/Estruturas/treapPersistent.md @@ -3,8 +3,8 @@ weight: 10 title: "Treap Persistent Implicita" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Estruturas/waveletTree.md b/content/docs/Estruturas/waveletTree.md index 5af5f8e..e985d2e 100644 --- a/content/docs/Estruturas/waveletTree.md +++ b/content/docs/Estruturas/waveletTree.md @@ -3,8 +3,8 @@ weight: 10 title: "Wavelet Tree" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Extra/_index.md b/content/docs/Extra/_index.md index 54153de..e9ac5b8 100644 --- a/content/docs/Extra/_index.md +++ b/content/docs/Extra/_index.md @@ -2,7 +2,7 @@ weight: 10 title: "Extra" draft: false -date: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" description: "" -publishdate: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T18:39:19-0300" --- diff --git a/content/docs/Grafos/LCA-HLD/_index.md b/content/docs/Grafos/LCA-HLD/_index.md new file mode 100644 index 0000000..1064392 --- /dev/null +++ b/content/docs/Grafos/LCA-HLD/_index.md @@ -0,0 +1,8 @@ +--- +weight: 10 +title: "LCA-HLD" +draft: false +date: "2024-05-09T18:39:19-0300" +description: "" +publishdate: "2024-05-09T18:39:19-0300" +--- diff --git a/content/docs/Grafos/LCA-HLD/hldAresta.md b/content/docs/Grafos/LCA-HLD/hldAresta.md new file mode 100644 index 0000000..3502595 --- /dev/null +++ b/content/docs/Grafos/LCA-HLD/hldAresta.md @@ -0,0 +1,91 @@ +--- +weight: 10 +title: "HLD - aresta" +draft: false +toc: true +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" +description: "" +--- + +## Sobre + SegTree de soma + + query / update de soma das arestas + + + + Complexidades: + + build - O(n) + + query_path - O(log^2 (n)) + + update_path - O(log^2 (n)) + + query_subtree - O(log(n)) + + update_subtree - O(log(n)) + + + + namespace seg { ... } + + + +Link original: [hldAresta.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/LCA-HLD/hldAresta.cpp) + +## Código +```cpp +namespace hld { + vector > g[MAX]; + int pos[MAX], sz[MAX]; + int sobe[MAX], pai[MAX]; + int h[MAX], v[MAX], t; + + void build_hld(int k, int p = -1, int f = 1) { + v[pos[k] = t++] = sobe[k]; sz[k] = 1; + for (auto& i : g[k]) if (i.first != p) { + auto [u, w] = i; + sobe[u] = w; pai[u] = k; + h[u] = (i == g[k][0] ? h[k] : u); + build_hld(u, k, f); sz[k] += sz[u]; + + if (sz[u] > sz[g[k][0].first] or g[k][0].first == p) + swap(i, g[k][0]); + } + if (p*f == -1) build_hld(h[k] = k, -1, t = 0); + } + void build(int root = 0) { + t = 0; + build_hld(root); + seg::build(t, v); + } + ll query_path(int a, int b) { + if (a == b) return 0; + if (pos[a] < pos[b]) swap(a, b); + + if (h[a] == h[b]) return seg::query(pos[b]+1, pos[a]); + return seg::query(pos[h[a]], pos[a]) + query_path(pai[h[a]], b); + } + void update_path(int a, int b, int x) { + if (a == b) return; + if (pos[a] < pos[b]) swap(a, b); + + if (h[a] == h[b]) return (void)seg::update(pos[b]+1, pos[a], x); + seg::update(pos[h[a]], pos[a], x); update_path(pai[h[a]], b, x); + } + ll query_subtree(int a) { + if (sz[a] == 1) return 0; + return seg::query(pos[a]+1, pos[a]+sz[a]-1); + } + void update_subtree(int a, int x) { + if (sz[a] == 1) return; + seg::update(pos[a]+1, pos[a]+sz[a]-1, x); + } + int lca(int a, int b) { + if (pos[a] < pos[b]) swap(a, b); + return h[a] == h[b] ? b : lca(pai[h[a]], b); + } +} +``` diff --git a/content/docs/Grafos/LCA-HLD/hldSemUpdate.md b/content/docs/Grafos/LCA-HLD/hldSemUpdate.md new file mode 100644 index 0000000..6869a94 --- /dev/null +++ b/content/docs/Grafos/LCA-HLD/hldSemUpdate.md @@ -0,0 +1,64 @@ +--- +weight: 10 +title: "HLD sem Update" +draft: false +toc: true +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" +description: "" +--- + +## Sobre + query de min do caminho + + + + Complexidades: + + build - O(n) + + query_path - O(log(n)) + + + +Link original: [hldSemUpdate.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/LCA-HLD/hldSemUpdate.cpp) + +## Código +```cpp +namespace hld { + vector > g[MAX]; + int pos[MAX], sz[MAX]; + int sobe[MAX], pai[MAX]; + int h[MAX], v[MAX], t; + int men[MAX], seg[2*MAX]; + + void build_hld(int k, int p = -1, int f = 1) { + v[pos[k] = t++] = sobe[k]; sz[k] = 1; + for (auto& i : g[k]) if (i.first != p) { + sobe[i.first] = i.second; pai[i.first] = k; + h[i.first] = (i == g[k][0] ? h[k] : i.first); + men[i.first] = (i == g[k][0] ? min(men[k], i.second) : i.second); + build_hld(i.first, k, f); sz[k] += sz[i.first]; + + if (sz[i.first] > sz[g[k][0].first] or g[k][0].first == p) + swap(i, g[k][0]); + } + if (p*f == -1) build_hld(h[k] = k, -1, t = 0); + } + void build(int root = 0) { + t = 0; + build_hld(root); + for (int i = 0; i < t; i++) seg[i+t] = v[i]; + for (int i = t-1; i; i--) seg[i] = min(seg[2*i], seg[2*i+1]); + } + int query_path(int a, int b) { + if (a == b) return INF; + if (pos[a] < pos[b]) swap(a, b); + + if (h[a] != h[b]) return min(men[a], query_path(pai[h[a]], b)); + int ans = INF, x = pos[b]+1+t, y = pos[a]+t; + for (; x <= y; ++x/=2, --y/=2) ans = min({ans, seg[x], seg[y]}); + return ans; + } +}; +``` diff --git a/content/docs/Grafos/LCA-HLD/hldVertice.md b/content/docs/Grafos/LCA-HLD/hldVertice.md new file mode 100644 index 0000000..46bbd46 --- /dev/null +++ b/content/docs/Grafos/LCA-HLD/hldVertice.md @@ -0,0 +1,85 @@ +--- +weight: 10 +title: "HLD - vertice" +draft: false +toc: true +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" +description: "" +--- + +## Sobre + SegTree de soma + + query / update de soma dos vertices + + + + Complexidades: + + build - O(n) + + query_path - O(log^2 (n)) + + update_path - O(log^2 (n)) + + query_subtree - O(log(n)) + + update_subtree - O(log(n)) + + + + namespace seg { ... } + + + +Link original: [hldVertice.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/LCA-HLD/hldVertice.cpp) + +## Código +```cpp +namespace hld { + vector g[MAX]; + int pos[MAX], sz[MAX]; + int peso[MAX], pai[MAX]; + int h[MAX], v[MAX], t; + + void build_hld(int k, int p = -1, int f = 1) { + v[pos[k] = t++] = peso[k]; sz[k] = 1; + for (auto& i : g[k]) if (i != p) { + pai[i] = k; + h[i] = (i == g[k][0] ? h[k] : i); + build_hld(i, k, f); sz[k] += sz[i]; + + if (sz[i] > sz[g[k][0]] or g[k][0] == p) swap(i, g[k][0]); + } + if (p*f == -1) build_hld(h[k] = k, -1, t = 0); + } + void build(int root = 0) { + t = 0; + build_hld(root); + seg::build(t, v); + } + ll query_path(int a, int b) { + if (pos[a] < pos[b]) swap(a, b); + + if (h[a] == h[b]) return seg::query(pos[b], pos[a]); + return seg::query(pos[h[a]], pos[a]) + query_path(pai[h[a]], b); + } + void update_path(int a, int b, int x) { + if (pos[a] < pos[b]) swap(a, b); + + if (h[a] == h[b]) return (void)seg::update(pos[b], pos[a], x); + seg::update(pos[h[a]], pos[a], x); update_path(pai[h[a]], b, x); + } + ll query_subtree(int a) { + return seg::query(pos[a], pos[a]+sz[a]-1); + } + void update_subtree(int a, int x) { + seg::update(pos[a], pos[a]+sz[a]-1, x); + } + int lca(int a, int b) { + if (pos[a] < pos[b]) swap(a, b); + return h[a] == h[b] ? b : lca(pai[h[a]], b); + } +} +``` diff --git a/content/docs/Grafos/LCA-HLD/lca.md b/content/docs/Grafos/LCA-HLD/lca.md new file mode 100644 index 0000000..e08f86e --- /dev/null +++ b/content/docs/Grafos/LCA-HLD/lca.md @@ -0,0 +1,90 @@ +--- +weight: 10 +title: "LCA com RMQ" +draft: false +toc: true +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" +description: "" +--- + +## Sobre + Assume que um vertice eh ancestral dele mesmo, ou seja, + + se a eh ancestral de b, lca(a, b) = a + + dist(a, b) retorna a distancia entre a e b + + + + Complexidades: + + build - O(n) + + lca - O(1) + + dist - O(1) + + + +Link original: [lca.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/LCA-HLD/lca.cpp) + +## Código +```cpp +template struct rmq { + vector v; + int n; static const int b = 30; + vector mask, t; + + int op(int x, int y) { return v[x] < v[y] ? x : y; } + int msb(int x) { return __builtin_clz(1)-__builtin_clz(x); } + rmq() {} + rmq(const vector& v_) : v(v_), n(v.size()), mask(n), t(n) { + for (int i = 0, at = 0; i < n; mask[i++] = at |= 1) { + at = (at<<1)&((1< g[MAX]; + int v[2*MAX], pos[MAX], dep[2*MAX]; + int t; + rmq RMQ; + + void dfs(int i, int d = 0, int p = -1) { + v[t] = i, pos[i] = t, dep[t++] = d; + for (int j : g[i]) if (j != p) { + dfs(j, d+1, i); + v[t] = i, dep[t++] = d; + } + } + void build(int n, int root) { + t = 0; + dfs(root); + RMQ = rmq(vector(dep, dep+2*n-1)); + } + int lca(int a, int b) { + a = pos[a], b = pos[b]; + return v[RMQ.query(min(a, b), max(a, b))]; + } + int dist(int a, int b) { + return dep[pos[a]] + dep[pos[b]] - 2*dep[pos[lca(a, b)]]; + } +} +``` diff --git a/content/docs/Grafos/LCA-HLD/lcaComBinaryLifting.md b/content/docs/Grafos/LCA-HLD/lcaComBinaryLifting.md new file mode 100644 index 0000000..cefb629 --- /dev/null +++ b/content/docs/Grafos/LCA-HLD/lcaComBinaryLifting.md @@ -0,0 +1,116 @@ +--- +weight: 10 +title: "LCA com binary lifting" +draft: false +toc: true +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" +description: "" +--- + +## Sobre + Assume que um vertice eh ancestral dele mesmo, ou seja, + + se a eh ancestral de b, lca(a, b) = a + + MAX2 = ceil(log(MAX)) + + + + Complexidades: + + build - O(n log(n)) + + lca - O(log(n)) + + + +Link original: [lcaComBinaryLifting.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/LCA-HLD/lcaComBinaryLifting.cpp) + +## Código +```cpp +vector > g(MAX); +int n, p; +int pai[MAX2][MAX]; +int in[MAX], out[MAX]; + +void dfs(int k) { + in[k] = p++; + for (int i = 0; i < (int) g[k].size(); i++) + if (in[g[k][i]] == -1) { + pai[0][g[k][i]] = k; + dfs(g[k][i]); + } + out[k] = p++; +} + +void build(int raiz) { + for (int i = 0; i < n; i++) pai[0][i] = i; + p = 0, memset(in, -1, sizeof in); + dfs(raiz); + + // pd dos pais + for (int k = 1; k < MAX2; k++) for (int i = 0; i < n; i++) + pai[k][i] = pai[k - 1][pai[k - 1][i]]; +} + +bool anc(int a, int b) { // se a eh ancestral de b + return in[a] <= in[b] and out[a] >= out[b]; +} + +int lca(int a, int b) { + if (anc(a, b)) return a; + if (anc(b, a)) return b; + + // sobe a + for (int k = MAX2 - 1; k >= 0; k--) + if (!anc(pai[k][a], b)) a = pai[k][a]; + + return pai[0][a]; +} + +// Alternativamente: +// 'binary lifting' gastando O(n) de memoria +// Da pra add folhas e fazer queries online +// 3 vezes o tempo do binary lifting normal +// +// build - O(n) +// kth, lca, dist - O(log(n)) + +int d[MAX], p[MAX], pp[MAX]; + +void set_root(int i) { p[i] = pp[i] = i, d[i] = 0; } + +void add_leaf(int i, int u) { + p[i] = u, d[i] = d[u]+1; + pp[i] = 2*d[pp[u]] == d[pp[pp[u]]]+d[u] ? pp[pp[u]] : u; +} + +int kth(int i, int k) { + int dd = max(0, d[i]-k); + while (d[i] > dd) i = d[pp[i]] >= dd ? pp[i] : p[i]; + return i; +} + +int lca(int a, int b) { + if (d[a] < d[b]) swap(a, b); + while (d[a] > d[b]) a = d[pp[a]] >= d[b] ? pp[a] : p[a]; + while (a != b) { + if (pp[a] != pp[b]) a = pp[a], b = pp[b]; + else a = p[a], b = p[b]; + } + return a; +} + +int dist(int a, int b) { return d[a]+d[b]-2*d[lca(a,b)]; } + +vector g[MAX]; + +void build(int i, int pai=-1) { + if (pai == -1) set_root(i); + for (int j : g[i]) if (j != pai) { + add_leaf(j, i); + build(j, i); + } +} +``` diff --git a/content/docs/Grafos/LCA-HLD/lcaComHld.md b/content/docs/Grafos/LCA-HLD/lcaComHld.md new file mode 100644 index 0000000..7dc3c81 --- /dev/null +++ b/content/docs/Grafos/LCA-HLD/lcaComHld.md @@ -0,0 +1,61 @@ +--- +weight: 10 +title: "LCA com HLD" +draft: false +toc: true +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" +description: "" +--- + +## Sobre + Assume que um vertice eh ancestral dele mesmo, ou seja, + + se a eh ancestral de b, lca(a, b) = a + + Para buildar pasta chamar build(root) + + anc(a, b) responde se 'a' eh ancestral de 'b' + + + + Complexidades: + + build - O(n) + + lca - O(log(n)) + + anc - O(1) + + + +Link original: [lcaComHld.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/LCA-HLD/lcaComHld.cpp) + +## Código +```cpp +vector g[MAX]; +int pos[MAX], h[MAX], sz[MAX]; +int pai[MAX], t; + +void build(int k, int p = -1, int f = 1) { + pos[k] = t++; sz[k] = 1; + for (int& i : g[k]) if (i != p) { + pai[i] = k; + h[i] = (i == g[k][0] ? h[k] : i); + build(i, k, f); sz[k] += sz[i]; + + if (sz[i] > sz[g[k][0]] or g[k][0] == p) swap(i, g[k][0]); + } + if (p*f == -1) t = 0, h[k] = k, build(k, -1, 0); +} + +int lca(int a, int b) { + if (pos[a] < pos[b]) swap(a, b); + return h[a] == h[b] ? b : lca(pai[h[a]], b); +} + +bool anc(int a, int b) { + return pos[a] <= pos[b] and pos[b] <= pos[a]+sz[a]-1; +} + +``` diff --git a/content/docs/Grafos/LCT/_index.md b/content/docs/Grafos/LCT/_index.md new file mode 100644 index 0000000..1b88271 --- /dev/null +++ b/content/docs/Grafos/LCT/_index.md @@ -0,0 +1,8 @@ +--- +weight: 10 +title: "LCT" +draft: false +date: "2024-05-09T18:39:18-0300" +description: "" +publishdate: "2024-05-09T18:39:18-0300" +--- diff --git a/content/docs/Grafos/LCT/lct.md b/content/docs/Grafos/LCT/lct.md new file mode 100644 index 0000000..af7c22b --- /dev/null +++ b/content/docs/Grafos/LCT/lct.md @@ -0,0 +1,73 @@ +--- +weight: 10 +title: "Link-cut Tree" +draft: false +toc: true +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" +description: "" +--- + +## Sobre + Link-cut tree padrao + + + + Todas as operacoes sao O(log(n)) amortizado + + + +Link original: [lct.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/LCT/lct.cpp) + +## Código +```cpp +namespace lct { + struct node { + int p, ch[2]; + node() { p = ch[0] = ch[1] = -1; } + }; + + node t[MAX]; + + bool is_root(int x) { + return t[x].p == -1 or (t[t[x].p].ch[0] != x and t[t[x].p].ch[1] != x); + } + void rotate(int x) { + int p = t[x].p, pp = t[p].p; + if (!is_root(p)) t[pp].ch[t[pp].ch[1] == p] = x; + bool d = t[p].ch[0] == x; + t[p].ch[!d] = t[x].ch[d], t[x].ch[d] = p; + if (t[p].ch[!d]+1) t[t[p].ch[!d]].p = p; + t[x].p = pp, t[p].p = x; + } + void splay(int x) { + while (!is_root(x)) { + int p = t[x].p, pp = t[p].p; + if (!is_root(p)) rotate((t[pp].ch[0] == p)^(t[p].ch[0] == x) ? x : p); + rotate(x); + } + } + int access(int v) { + int last = -1; + for (int w = v; w+1; last = w, splay(v), w = t[v].p) + splay(w), t[w].ch[1] = (last == -1 ? -1 : v); + return last; + } + int find_root(int v) { + access(v); + while (t[v].ch[0]+1) v = t[v].ch[0]; + return splay(v), v; + } + void link(int v, int w) { // v deve ser raiz + access(v); + t[v].p = w; + } + void cut(int v) { // remove aresta de v pro pai + access(v); + t[v].ch[0] = t[t[v].ch[0]].p = -1; + } + int lca(int v, int w) { + return access(v), access(w); + } +} +``` diff --git a/content/docs/Grafos/LCT/lctAresta.md b/content/docs/Grafos/LCT/lctAresta.md new file mode 100644 index 0000000..2d45589 --- /dev/null +++ b/content/docs/Grafos/LCT/lctAresta.md @@ -0,0 +1,143 @@ +--- +weight: 10 +title: "Link-cut Tree - aresta" +draft: false +toc: true +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" +description: "" +--- + +## Sobre + Valores nas arestas + + rootify(v) torna v a raiz de sua arvore + + query(v, w) retorna a soma do caminho v--w + + update(v, w, x) soma x nas arestas do caminho v--w + + + + Todas as operacoes sao O(log(n)) amortizado + + + +Link original: [lctAresta.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/LCT/lctAresta.cpp) + +## Código +```cpp +namespace lct { + struct node { + int p, ch[2]; + ll val, sub; + bool rev; + int sz, ar; + ll lazy; + node() {} + node(int v, int ar_) : + p(-1), val(v), sub(v), rev(0), sz(ar_), ar(ar_), lazy(0) { + ch[0] = ch[1] = -1; + } + }; + + node t[2*MAX]; // MAXN + MAXQ + map, int> aresta; + int sz; + + void prop(int x) { + if (t[x].lazy) { + if (t[x].ar) t[x].val += t[x].lazy; + t[x].sub += t[x].lazy*t[x].sz; + if (t[x].ch[0]+1) t[t[x].ch[0]].lazy += t[x].lazy; + if (t[x].ch[1]+1) t[t[x].ch[1]].lazy += t[x].lazy; + } + if (t[x].rev) { + swap(t[x].ch[0], t[x].ch[1]); + if (t[x].ch[0]+1) t[t[x].ch[0]].rev ^= 1; + if (t[x].ch[1]+1) t[t[x].ch[1]].rev ^= 1; + } + t[x].lazy = 0, t[x].rev = 0; + } + void update(int x) { + t[x].sz = t[x].ar, t[x].sub = t[x].val; + for (int i = 0; i < 2; i++) if (t[x].ch[i]+1) { + prop(t[x].ch[i]); + t[x].sz += t[t[x].ch[i]].sz; + t[x].sub += t[t[x].ch[i]].sub; + } + } + bool is_root(int x) { + return t[x].p == -1 or (t[t[x].p].ch[0] != x and t[t[x].p].ch[1] != x); + } + void rotate(int x) { + int p = t[x].p, pp = t[p].p; + if (!is_root(p)) t[pp].ch[t[pp].ch[1] == p] = x; + bool d = t[p].ch[0] == x; + t[p].ch[!d] = t[x].ch[d], t[x].ch[d] = p; + if (t[p].ch[!d]+1) t[t[p].ch[!d]].p = p; + t[x].p = pp, t[p].p = x; + update(p), update(x); + } + int splay(int x) { + while (!is_root(x)) { + int p = t[x].p, pp = t[p].p; + if (!is_root(p)) prop(pp); + prop(p), prop(x); + if (!is_root(p)) rotate((t[pp].ch[0] == p)^(t[p].ch[0] == x) ? x : p); + rotate(x); + } + return prop(x), x; + } + int access(int v) { + int last = -1; + for (int w = v; w+1; update(last = w), splay(v), w = t[v].p) + splay(w), t[w].ch[1] = (last == -1 ? -1 : v); + return last; + } + void make_tree(int v, int w=0, int ar=0) { t[v] = node(w, ar); } + int find_root(int v) { + access(v), prop(v); + while (t[v].ch[0]+1) v = t[v].ch[0], prop(v); + return splay(v); + } + bool conn(int v, int w) { + access(v), access(w); + return v == w ? true : t[v].p != -1; + } + void rootify(int v) { + access(v); + t[v].rev ^= 1; + } + ll query(int v, int w) { + rootify(w), access(v); + return t[v].sub; + } + void update(int v, int w, int x) { + rootify(w), access(v); + t[v].lazy += x; + } + void link_(int v, int w) { + rootify(w); + t[w].p = v; + } + void link(int v, int w, int x) { // v--w com peso x + int id = MAX + sz++; + aresta[make_pair(v, w)] = id; + make_tree(id, x, 1); + link_(v, id), link_(id, w); + } + void cut_(int v, int w) { + rootify(w), access(v); + t[v].ch[0] = t[t[v].ch[0]].p = -1; + } + void cut(int v, int w) { + int id = aresta[make_pair(v, w)]; + cut_(v, id), cut_(id, w); + } + int lca(int v, int w) { + access(v); + return access(w); + } +} +``` diff --git a/content/docs/Grafos/LCT/lctVertice.md b/content/docs/Grafos/LCT/lctVertice.md new file mode 100644 index 0000000..85a0a71 --- /dev/null +++ b/content/docs/Grafos/LCT/lctVertice.md @@ -0,0 +1,133 @@ +--- +weight: 10 +title: "Link-cut Tree - vertice" +draft: false +toc: true +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" +description: "" +--- + +## Sobre + Valores nos vertices + + make_tree(v, w) cria uma nova arvore com um + + vertice soh com valor 'w' + + rootify(v) torna v a raiz de sua arvore + + query(v, w) retorna a soma do caminho v--w + + update(v, w, x) soma x nos vertices do caminho v--w + + + + Todas as operacoes sao O(log(n)) amortizado + + + +Link original: [lctVertice.cpp](https://github.com/brunomaletta/Biblioteca/tree/master/Codigo/Grafos/LCT/lctVertice.cpp) + +## Código +```cpp +namespace lct { + struct node { + int p, ch[2]; + ll val, sub; + bool rev; + int sz; + ll lazy; + node() {} + node(int v) : p(-1), val(v), sub(v), rev(0), sz(1), lazy(0) { + ch[0] = ch[1] = -1; + } + }; + + node t[MAX]; + + void prop(int x) { + if (t[x].lazy) { + t[x].val += t[x].lazy, t[x].sub += t[x].lazy*t[x].sz; + if (t[x].ch[0]+1) t[t[x].ch[0]].lazy += t[x].lazy; + if (t[x].ch[1]+1) t[t[x].ch[1]].lazy += t[x].lazy; + } + if (t[x].rev) { + swap(t[x].ch[0], t[x].ch[1]); + if (t[x].ch[0]+1) t[t[x].ch[0]].rev ^= 1; + if (t[x].ch[1]+1) t[t[x].ch[1]].rev ^= 1; + } + t[x].lazy = 0, t[x].rev = 0; + } + void update(int x) { + t[x].sz = 1, t[x].sub = t[x].val; + for (int i = 0; i < 2; i++) if (t[x].ch[i]+1) { + prop(t[x].ch[i]); + t[x].sz += t[t[x].ch[i]].sz; + t[x].sub += t[t[x].ch[i]].sub; + } + } + bool is_root(int x) { + return t[x].p == -1 or (t[t[x].p].ch[0] != x and t[t[x].p].ch[1] != x); + } + void rotate(int x) { + int p = t[x].p, pp = t[p].p; + if (!is_root(p)) t[pp].ch[t[pp].ch[1] == p] = x; + bool d = t[p].ch[0] == x; + t[p].ch[!d] = t[x].ch[d], t[x].ch[d] = p; + if (t[p].ch[!d]+1) t[t[p].ch[!d]].p = p; + t[x].p = pp, t[p].p = x; + update(p), update(x); + } + int splay(int x) { + while (!is_root(x)) { + int p = t[x].p, pp = t[p].p; + if (!is_root(p)) prop(pp); + prop(p), prop(x); + if (!is_root(p)) rotate((t[pp].ch[0] == p)^(t[p].ch[0] == x) ? x : p); + rotate(x); + } + return prop(x), x; + } + int access(int v) { + int last = -1; + for (int w = v; w+1; update(last = w), splay(v), w = t[v].p) + splay(w), t[w].ch[1] = (last == -1 ? -1 : v); + return last; + } + void make_tree(int v, int w) { t[v] = node(w); } + int find_root(int v) { + access(v), prop(v); + while (t[v].ch[0]+1) v = t[v].ch[0], prop(v); + return splay(v); + } + bool connected(int v, int w) { + access(v), access(w); + return v == w ? true : t[v].p != -1; + } + void rootify(int v) { + access(v); + t[v].rev ^= 1; + } + ll query(int v, int w) { + rootify(w), access(v); + return t[v].sub; + } + void update(int v, int w, int x) { + rootify(w), access(v); + t[v].lazy += x; + } + void link(int v, int w) { + rootify(w); + t[w].p = v; + } + void cut(int v, int w) { + rootify(w), access(v); + t[v].ch[0] = t[t[v].ch[0]].p = -1; + } + int lca(int v, int w) { + access(v); + return access(w); + } +} +``` diff --git a/content/docs/Grafos/_index.md b/content/docs/Grafos/_index.md index c5ae2af..dfd5d7d 100644 --- a/content/docs/Grafos/_index.md +++ b/content/docs/Grafos/_index.md @@ -2,7 +2,7 @@ weight: 10 title: "Grafos" draft: false -date: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" description: "" -publishdate: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T18:39:18-0300" --- diff --git a/content/docs/Grafos/articulationPoints.md b/content/docs/Grafos/articulationPoints.md index 08e321e..ec2e542 100644 --- a/content/docs/Grafos/articulationPoints.md +++ b/content/docs/Grafos/articulationPoints.md @@ -3,8 +3,8 @@ weight: 10 title: "Articulation Points" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Grafos/bellmanFord.md b/content/docs/Grafos/bellmanFord.md index e69f80e..1feef1d 100644 --- a/content/docs/Grafos/bellmanFord.md +++ b/content/docs/Grafos/bellmanFord.md @@ -3,8 +3,8 @@ weight: 10 title: "Bellman-Ford" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Grafos/blockCutTree.md b/content/docs/Grafos/blockCutTree.md index 7398427..88057de 100644 --- a/content/docs/Grafos/blockCutTree.md +++ b/content/docs/Grafos/blockCutTree.md @@ -3,8 +3,8 @@ weight: 10 title: "Block-Cut Tree" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Grafos/blossom.md b/content/docs/Grafos/blossom.md index 460db1e..b91bfdf 100644 --- a/content/docs/Grafos/blossom.md +++ b/content/docs/Grafos/blossom.md @@ -3,8 +3,8 @@ weight: 10 title: "Blossom" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Grafos/center.md b/content/docs/Grafos/center.md index f90f3f8..1a9c231 100644 --- a/content/docs/Grafos/center.md +++ b/content/docs/Grafos/center.md @@ -3,8 +3,8 @@ weight: 10 title: "Centro de arvore" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Grafos/centroid.md b/content/docs/Grafos/centroid.md index 932758c..80ce3bb 100644 --- a/content/docs/Grafos/centroid.md +++ b/content/docs/Grafos/centroid.md @@ -3,8 +3,8 @@ weight: 10 title: "Centroid" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Grafos/centroidDecomp.md b/content/docs/Grafos/centroidDecomp.md index 6f536a2..aa3b614 100644 --- a/content/docs/Grafos/centroidDecomp.md +++ b/content/docs/Grafos/centroidDecomp.md @@ -3,8 +3,8 @@ weight: 10 title: "Centroid decomposition" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Grafos/centroidTree.md b/content/docs/Grafos/centroidTree.md index 36875ca..28653ad 100644 --- a/content/docs/Grafos/centroidTree.md +++ b/content/docs/Grafos/centroidTree.md @@ -3,8 +3,8 @@ weight: 10 title: "Centroid Tree" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Grafos/cover.md b/content/docs/Grafos/cover.md index eb33242..a3615dd 100644 --- a/content/docs/Grafos/cover.md +++ b/content/docs/Grafos/cover.md @@ -3,8 +3,8 @@ weight: 10 title: "Vertex cover" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Grafos/dijkstra.md b/content/docs/Grafos/dijkstra.md index 74a5a7a..1b4aa5d 100644 --- a/content/docs/Grafos/dijkstra.md +++ b/content/docs/Grafos/dijkstra.md @@ -3,8 +3,8 @@ weight: 10 title: "Dijkstra" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Grafos/dinitz.md b/content/docs/Grafos/dinitz.md index 57a8d81..e9b274b 100644 --- a/content/docs/Grafos/dinitz.md +++ b/content/docs/Grafos/dinitz.md @@ -3,8 +3,8 @@ weight: 10 title: "Dinitz" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Grafos/directedMst.md b/content/docs/Grafos/directedMst.md index 9f60f23..7106f71 100644 --- a/content/docs/Grafos/directedMst.md +++ b/content/docs/Grafos/directedMst.md @@ -3,8 +3,8 @@ weight: 10 title: "AGM Direcionada" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Grafos/dominatorTree.md b/content/docs/Grafos/dominatorTree.md index 6591e08..20d79c6 100644 --- a/content/docs/Grafos/dominatorTree.md +++ b/content/docs/Grafos/dominatorTree.md @@ -3,8 +3,8 @@ weight: 10 title: "Dominator Tree" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Grafos/eulerPath.md b/content/docs/Grafos/eulerPath.md index d2be1a7..61bc593 100644 --- a/content/docs/Grafos/eulerPath.md +++ b/content/docs/Grafos/eulerPath.md @@ -3,8 +3,8 @@ weight: 10 title: "Euler Path / Euler Cycle" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Grafos/eulerTourTree.md b/content/docs/Grafos/eulerTourTree.md index a5080a3..3b88dc2 100644 --- a/content/docs/Grafos/eulerTourTree.md +++ b/content/docs/Grafos/eulerTourTree.md @@ -3,8 +3,8 @@ weight: 10 title: "Euler Tour Tree" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Grafos/floydWarshall.md b/content/docs/Grafos/floydWarshall.md index 2cd0ece..57056c7 100644 --- a/content/docs/Grafos/floydWarshall.md +++ b/content/docs/Grafos/floydWarshall.md @@ -3,8 +3,8 @@ weight: 10 title: "Floyd-Warshall" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Grafos/functionalGraph.md b/content/docs/Grafos/functionalGraph.md index 37b78c8..3ca1ff5 100644 --- a/content/docs/Grafos/functionalGraph.md +++ b/content/docs/Grafos/functionalGraph.md @@ -3,8 +3,8 @@ weight: 10 title: "Functional Graph" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Grafos/hopcroftKarp.md b/content/docs/Grafos/hopcroftKarp.md index 13c67aa..9c109cd 100644 --- a/content/docs/Grafos/hopcroftKarp.md +++ b/content/docs/Grafos/hopcroftKarp.md @@ -3,8 +3,8 @@ weight: 10 title: "Hopcroft Karp" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Grafos/johnson.md b/content/docs/Grafos/johnson.md index 8d26434..0656bcb 100644 --- a/content/docs/Grafos/johnson.md +++ b/content/docs/Grafos/johnson.md @@ -3,8 +3,8 @@ weight: 10 title: "Johnson" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Grafos/kosaraju.md b/content/docs/Grafos/kosaraju.md index 24acb45..7022718 100644 --- a/content/docs/Grafos/kosaraju.md +++ b/content/docs/Grafos/kosaraju.md @@ -3,8 +3,8 @@ weight: 10 title: "Kosaraju" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Grafos/kruskal.md b/content/docs/Grafos/kruskal.md index 075ac8d..efca62a 100644 --- a/content/docs/Grafos/kruskal.md +++ b/content/docs/Grafos/kruskal.md @@ -3,8 +3,8 @@ weight: 10 title: "Kruskal" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Grafos/kuhn.md b/content/docs/Grafos/kuhn.md index 284dc74..edb7fac 100644 --- a/content/docs/Grafos/kuhn.md +++ b/content/docs/Grafos/kuhn.md @@ -3,8 +3,8 @@ weight: 10 title: "Kuhn" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Grafos/linetree.md b/content/docs/Grafos/linetree.md index d58bd0d..d00f37a 100644 --- a/content/docs/Grafos/linetree.md +++ b/content/docs/Grafos/linetree.md @@ -3,8 +3,8 @@ weight: 10 title: "Line Tree" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Grafos/lowerBoundMaxFlow.md b/content/docs/Grafos/lowerBoundMaxFlow.md index d44ce6e..d12c0bf 100644 --- a/content/docs/Grafos/lowerBoundMaxFlow.md +++ b/content/docs/Grafos/lowerBoundMaxFlow.md @@ -3,8 +3,8 @@ weight: 10 title: "Max flow com lower bound" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Grafos/minCostMaxFlow.md b/content/docs/Grafos/minCostMaxFlow.md index b3b3309..f6d4804 100644 --- a/content/docs/Grafos/minCostMaxFlow.md +++ b/content/docs/Grafos/minCostMaxFlow.md @@ -3,8 +3,8 @@ weight: 10 title: "MinCostMaxFlow" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Grafos/prufer.md b/content/docs/Grafos/prufer.md index d3cccdd..3204a1e 100644 --- a/content/docs/Grafos/prufer.md +++ b/content/docs/Grafos/prufer.md @@ -3,8 +3,8 @@ weight: 10 title: "Prufer code" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Grafos/sack.md b/content/docs/Grafos/sack.md index 1d1f7d7..2c00b5a 100644 --- a/content/docs/Grafos/sack.md +++ b/content/docs/Grafos/sack.md @@ -3,8 +3,8 @@ weight: 10 title: "Sack (DSU em arvores)" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Grafos/stableMarriage.md b/content/docs/Grafos/stableMarriage.md index 09aaf77..21240d5 100644 --- a/content/docs/Grafos/stableMarriage.md +++ b/content/docs/Grafos/stableMarriage.md @@ -3,8 +3,8 @@ weight: 10 title: "Stable Marriage" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Grafos/tarjan.md b/content/docs/Grafos/tarjan.md index 384870a..233ad82 100644 --- a/content/docs/Grafos/tarjan.md +++ b/content/docs/Grafos/tarjan.md @@ -3,8 +3,8 @@ weight: 10 title: "Tarjan para SCC" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Grafos/topoSort.md b/content/docs/Grafos/topoSort.md index 6be11bf..37f03eb 100644 --- a/content/docs/Grafos/topoSort.md +++ b/content/docs/Grafos/topoSort.md @@ -3,8 +3,8 @@ weight: 10 title: "Topological Sort" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Grafos/treeIsomorf.md b/content/docs/Grafos/treeIsomorf.md index d3a43d0..7e2f34b 100644 --- a/content/docs/Grafos/treeIsomorf.md +++ b/content/docs/Grafos/treeIsomorf.md @@ -3,8 +3,8 @@ weight: 10 title: "Isomorfismo de arvores" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Grafos/virtualTree.md b/content/docs/Grafos/virtualTree.md index 4c2f998..0e3f4c6 100644 --- a/content/docs/Grafos/virtualTree.md +++ b/content/docs/Grafos/virtualTree.md @@ -3,8 +3,8 @@ weight: 10 title: "Virtual Tree" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Matematica/2sat.md b/content/docs/Matematica/2sat.md index 585d5e6..6a86f6c 100644 --- a/content/docs/Matematica/2sat.md +++ b/content/docs/Matematica/2sat.md @@ -3,8 +3,8 @@ weight: 10 title: "2-SAT" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Matematica/_index.md b/content/docs/Matematica/_index.md index eba21c7..3ba7975 100644 --- a/content/docs/Matematica/_index.md +++ b/content/docs/Matematica/_index.md @@ -2,7 +2,7 @@ weight: 10 title: "Matematica" draft: false -date: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" description: "" -publishdate: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T18:39:19-0300" --- diff --git a/content/docs/Matematica/berlekampMassey.md b/content/docs/Matematica/berlekampMassey.md index 65409a0..f782fd5 100644 --- a/content/docs/Matematica/berlekampMassey.md +++ b/content/docs/Matematica/berlekampMassey.md @@ -3,8 +3,8 @@ weight: 10 title: "Berlekamp-Massey" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Matematica/chinese.md b/content/docs/Matematica/chinese.md index fa9985b..7679686 100644 --- a/content/docs/Matematica/chinese.md +++ b/content/docs/Matematica/chinese.md @@ -3,8 +3,8 @@ weight: 10 title: "Teorema Chines do Resto" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Matematica/convolution.md b/content/docs/Matematica/convolution.md index dbb3c2f..2e9373d 100644 --- a/content/docs/Matematica/convolution.md +++ b/content/docs/Matematica/convolution.md @@ -3,8 +3,8 @@ weight: 10 title: "FFT" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Matematica/coprimeBasis.md b/content/docs/Matematica/coprimeBasis.md index 550aa26..7119109 100644 --- a/content/docs/Matematica/coprimeBasis.md +++ b/content/docs/Matematica/coprimeBasis.md @@ -3,8 +3,8 @@ weight: 10 title: "Coprime Basis" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Matematica/crivo.md b/content/docs/Matematica/crivo.md index a627d20..33cdc06 100644 --- a/content/docs/Matematica/crivo.md +++ b/content/docs/Matematica/crivo.md @@ -3,8 +3,8 @@ weight: 10 title: "Crivo de Eratosthenes" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Matematica/cycleDetection.md b/content/docs/Matematica/cycleDetection.md index 61b4eb7..1dc6f57 100644 --- a/content/docs/Matematica/cycleDetection.md +++ b/content/docs/Matematica/cycleDetection.md @@ -3,8 +3,8 @@ weight: 10 title: "Deteccao de ciclo - Tortoise and Hare" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Matematica/diofantina.md b/content/docs/Matematica/diofantina.md index e92cd0d..39090c6 100644 --- a/content/docs/Matematica/diofantina.md +++ b/content/docs/Matematica/diofantina.md @@ -3,8 +3,8 @@ weight: 10 title: "Equacao Diofantina Linear" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Matematica/divisionTrick.md b/content/docs/Matematica/divisionTrick.md index 74b06af..8d68e0e 100644 --- a/content/docs/Matematica/divisionTrick.md +++ b/content/docs/Matematica/divisionTrick.md @@ -3,8 +3,8 @@ weight: 10 title: "Division Trick" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Matematica/evalInterpol.md b/content/docs/Matematica/evalInterpol.md index 3459342..f81015a 100644 --- a/content/docs/Matematica/evalInterpol.md +++ b/content/docs/Matematica/evalInterpol.md @@ -3,8 +3,8 @@ weight: 10 title: "Avaliacao de Interpolacao" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Matematica/fastPow.md b/content/docs/Matematica/fastPow.md index 5449dec..c53c1d9 100644 --- a/content/docs/Matematica/fastPow.md +++ b/content/docs/Matematica/fastPow.md @@ -3,8 +3,8 @@ weight: 10 title: "Exponenciacao rapida" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Matematica/fwht.md b/content/docs/Matematica/fwht.md index 1f80321..6ee3f4c 100644 --- a/content/docs/Matematica/fwht.md +++ b/content/docs/Matematica/fwht.md @@ -3,8 +3,8 @@ weight: 10 title: "Fast Walsh Hadamard Transform" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Matematica/gauss.md b/content/docs/Matematica/gauss.md index 3566f18..46ec273 100644 --- a/content/docs/Matematica/gauss.md +++ b/content/docs/Matematica/gauss.md @@ -3,8 +3,8 @@ weight: 10 title: "Gauss" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Matematica/gaussZ2.md b/content/docs/Matematica/gaussZ2.md index e0444ce..9e2a942 100644 --- a/content/docs/Matematica/gaussZ2.md +++ b/content/docs/Matematica/gaussZ2.md @@ -3,8 +3,8 @@ weight: 10 title: "Gauss - Z2" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Matematica/gcdEstendido.md b/content/docs/Matematica/gcdEstendido.md index 634a8fa..aec5020 100644 --- a/content/docs/Matematica/gcdEstendido.md +++ b/content/docs/Matematica/gcdEstendido.md @@ -3,8 +3,8 @@ weight: 10 title: "Euclides estendido" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Matematica/gcdLcmConvolution.md b/content/docs/Matematica/gcdLcmConvolution.md index 7cfc0f3..aeeeffa 100644 --- a/content/docs/Matematica/gcdLcmConvolution.md +++ b/content/docs/Matematica/gcdLcmConvolution.md @@ -3,8 +3,8 @@ weight: 10 title: "Convolucao de GCD / LCM" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Matematica/integral.md b/content/docs/Matematica/integral.md index 2e9c9f6..ca4959d 100644 --- a/content/docs/Matematica/integral.md +++ b/content/docs/Matematica/integral.md @@ -3,8 +3,8 @@ weight: 10 title: "Integracao Numerica" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Matematica/karatsuba.md b/content/docs/Matematica/karatsuba.md index 4c314ef..d447075 100644 --- a/content/docs/Matematica/karatsuba.md +++ b/content/docs/Matematica/karatsuba.md @@ -3,8 +3,8 @@ weight: 10 title: "Karatsuba" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Matematica/logDiscreto.md b/content/docs/Matematica/logDiscreto.md index 265150f..261ffd1 100644 --- a/content/docs/Matematica/logDiscreto.md +++ b/content/docs/Matematica/logDiscreto.md @@ -3,8 +3,8 @@ weight: 10 title: "Logaritmo Discreto" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Matematica/millerRabin.md b/content/docs/Matematica/millerRabin.md index 689d004..184b230 100644 --- a/content/docs/Matematica/millerRabin.md +++ b/content/docs/Matematica/millerRabin.md @@ -3,8 +3,8 @@ weight: 10 title: "Miller-Rabin" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Matematica/modInverse.md b/content/docs/Matematica/modInverse.md index 068639e..7d4ad17 100644 --- a/content/docs/Matematica/modInverse.md +++ b/content/docs/Matematica/modInverse.md @@ -3,8 +3,8 @@ weight: 10 title: "Inverso Modular" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Matematica/mulmod.md b/content/docs/Matematica/mulmod.md index b15372d..beb382b 100644 --- a/content/docs/Matematica/mulmod.md +++ b/content/docs/Matematica/mulmod.md @@ -3,8 +3,8 @@ weight: 10 title: "Produto de dois long long mod m" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Matematica/multipointEvaluation.md b/content/docs/Matematica/multipointEvaluation.md index 2769213..e4214c7 100644 --- a/content/docs/Matematica/multipointEvaluation.md +++ b/content/docs/Matematica/multipointEvaluation.md @@ -3,8 +3,8 @@ weight: 10 title: "Multipoint Evaluation And Interpolation" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Matematica/ntt.md b/content/docs/Matematica/ntt.md index 671ad0b..5d183ac 100644 --- a/content/docs/Matematica/ntt.md +++ b/content/docs/Matematica/ntt.md @@ -3,8 +3,8 @@ weight: 10 title: "NTT" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Matematica/pollardrho.md b/content/docs/Matematica/pollardrho.md index 8b58941..eec4181 100644 --- a/content/docs/Matematica/pollardrho.md +++ b/content/docs/Matematica/pollardrho.md @@ -3,8 +3,8 @@ weight: 10 title: "Pollard's Rho Alg" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Matematica/powerSeries.md b/content/docs/Matematica/powerSeries.md index ec0c28c..e655d9b 100644 --- a/content/docs/Matematica/powerSeries.md +++ b/content/docs/Matematica/powerSeries.md @@ -3,8 +3,8 @@ weight: 10 title: "Operacoes em Polinomios e Series de Potencias" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Matematica/probabilityBinomial.md b/content/docs/Matematica/probabilityBinomial.md index e3978fc..fcf4480 100644 --- a/content/docs/Matematica/probabilityBinomial.md +++ b/content/docs/Matematica/probabilityBinomial.md @@ -3,8 +3,8 @@ weight: 10 title: "Binomial Distribution" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Matematica/simplex.md b/content/docs/Matematica/simplex.md index 949468d..9902ba0 100644 --- a/content/docs/Matematica/simplex.md +++ b/content/docs/Matematica/simplex.md @@ -3,8 +3,8 @@ weight: 10 title: "Simplex" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Matematica/totiente.md b/content/docs/Matematica/totiente.md index 8e87af4..941236c 100644 --- a/content/docs/Matematica/totiente.md +++ b/content/docs/Matematica/totiente.md @@ -3,8 +3,8 @@ weight: 10 title: "Totiente" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Primitivas/_index.md b/content/docs/Primitivas/_index.md index 7754b7a..29fd092 100644 --- a/content/docs/Primitivas/_index.md +++ b/content/docs/Primitivas/_index.md @@ -2,7 +2,7 @@ weight: 10 title: "Primitivas" draft: false -date: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" description: "" -publishdate: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T18:39:19-0300" --- diff --git a/content/docs/Primitivas/bigint.md b/content/docs/Primitivas/bigint.md index 131ef21..a086633 100644 --- a/content/docs/Primitivas/bigint.md +++ b/content/docs/Primitivas/bigint.md @@ -3,8 +3,8 @@ weight: 10 title: "Big Integer" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Primitivas/calendario.md b/content/docs/Primitivas/calendario.md index c9eeb07..03278de 100644 --- a/content/docs/Primitivas/calendario.md +++ b/content/docs/Primitivas/calendario.md @@ -3,8 +3,8 @@ weight: 10 title: "Calendario" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Primitivas/frac.md b/content/docs/Primitivas/frac.md index 7a7d8c4..8a3b94d 100644 --- a/content/docs/Primitivas/frac.md +++ b/content/docs/Primitivas/frac.md @@ -3,8 +3,8 @@ weight: 10 title: "Fracao" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Primitivas/geometria.md b/content/docs/Primitivas/geometria.md index 56e4cce..974b616 100644 --- a/content/docs/Primitivas/geometria.md +++ b/content/docs/Primitivas/geometria.md @@ -3,8 +3,8 @@ weight: 10 title: "Geometria" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Primitivas/geometria3d.md b/content/docs/Primitivas/geometria3d.md index 1f2cfd4..2dd56fd 100644 --- a/content/docs/Primitivas/geometria3d.md +++ b/content/docs/Primitivas/geometria3d.md @@ -3,8 +3,8 @@ weight: 10 title: "Geometria 3D" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Primitivas/geometriaInt.md b/content/docs/Primitivas/geometriaInt.md index 9a9cdcd..6563dd3 100644 --- a/content/docs/Primitivas/geometriaInt.md +++ b/content/docs/Primitivas/geometriaInt.md @@ -3,8 +3,8 @@ weight: 10 title: "Geometria - inteiro" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Primitivas/matrix.md b/content/docs/Primitivas/matrix.md index 7746fa7..4289488 100644 --- a/content/docs/Primitivas/matrix.md +++ b/content/docs/Primitivas/matrix.md @@ -3,8 +3,8 @@ weight: 10 title: "Matriz" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Primitivas/matroid.md b/content/docs/Primitivas/matroid.md index 91e58e0..7dd856e 100644 --- a/content/docs/Primitivas/matroid.md +++ b/content/docs/Primitivas/matroid.md @@ -3,8 +3,8 @@ weight: 10 title: "Matroid" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Primitivas/modularArithmetic.md b/content/docs/Primitivas/modularArithmetic.md index 36403a7..3ad12cd 100644 --- a/content/docs/Primitivas/modularArithmetic.md +++ b/content/docs/Primitivas/modularArithmetic.md @@ -3,8 +3,8 @@ weight: 10 title: "Aritmetica Modular" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:19-0300" +publishdate: "2024-05-09T18:39:19-0300" description: "" --- diff --git a/content/docs/Problemas/_index.md b/content/docs/Problemas/_index.md index 981b5b3..652168d 100644 --- a/content/docs/Problemas/_index.md +++ b/content/docs/Problemas/_index.md @@ -2,7 +2,7 @@ weight: 10 title: "Problemas" draft: false -date: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" description: "" -publishdate: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T18:39:18-0300" --- diff --git a/content/docs/Problemas/additionChain.md b/content/docs/Problemas/additionChain.md index 0ab4e0e..6acd74d 100644 --- a/content/docs/Problemas/additionChain.md +++ b/content/docs/Problemas/additionChain.md @@ -3,8 +3,8 @@ weight: 10 title: "Shortest Addition Chain" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/angleRange.md b/content/docs/Problemas/angleRange.md index 930435e..736e4a9 100644 --- a/content/docs/Problemas/angleRange.md +++ b/content/docs/Problemas/angleRange.md @@ -3,8 +3,8 @@ weight: 10 title: "Angle Range Intersection" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/areaHistograma.md b/content/docs/Problemas/areaHistograma.md index feab6f5..ad8b503 100644 --- a/content/docs/Problemas/areaHistograma.md +++ b/content/docs/Problemas/areaHistograma.md @@ -3,8 +3,8 @@ weight: 10 title: "Area Maxima de Histograma" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/areaUniaoRetangulo.md b/content/docs/Problemas/areaUniaoRetangulo.md index 03e0a1a..b1d0241 100644 --- a/content/docs/Problemas/areaUniaoRetangulo.md +++ b/content/docs/Problemas/areaUniaoRetangulo.md @@ -3,8 +3,8 @@ weight: 10 title: "Area da Uniao de Retangulos" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/binomial.md b/content/docs/Problemas/binomial.md index 1970439..c43a871 100644 --- a/content/docs/Problemas/binomial.md +++ b/content/docs/Problemas/binomial.md @@ -3,8 +3,8 @@ weight: 10 title: "Binomial modular" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/closestPairOfPoints.md b/content/docs/Problemas/closestPairOfPoints.md index 8f681c8..779dfec 100644 --- a/content/docs/Problemas/closestPairOfPoints.md +++ b/content/docs/Problemas/closestPairOfPoints.md @@ -3,8 +3,8 @@ weight: 10 title: "Closest pair of points" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/conectividadeDinamica.md b/content/docs/Problemas/conectividadeDinamica.md index dba7f96..75ef2d2 100644 --- a/content/docs/Problemas/conectividadeDinamica.md +++ b/content/docs/Problemas/conectividadeDinamica.md @@ -3,8 +3,8 @@ weight: 10 title: "Conectividade Dinamica DC" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/conectividadeDinamica2.md b/content/docs/Problemas/conectividadeDinamica2.md index 864718d..ccf6350 100644 --- a/content/docs/Problemas/conectividadeDinamica2.md +++ b/content/docs/Problemas/conectividadeDinamica2.md @@ -3,8 +3,8 @@ weight: 10 title: "Conectividade Dinamica LCT" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/deBrujin.md b/content/docs/Problemas/deBrujin.md index 8f055e5..d1ca3e0 100644 --- a/content/docs/Problemas/deBrujin.md +++ b/content/docs/Problemas/deBrujin.md @@ -3,8 +3,8 @@ weight: 10 title: "Sequencia de de Brujin" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/delaunay.md b/content/docs/Problemas/delaunay.md index 48f06da..d3eb8a1 100644 --- a/content/docs/Problemas/delaunay.md +++ b/content/docs/Problemas/delaunay.md @@ -3,8 +3,8 @@ weight: 10 title: "Triangulacao de Delaunay" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/distinct.md b/content/docs/Problemas/distinct.md index 8cc894b..093b0a4 100644 --- a/content/docs/Problemas/distinct.md +++ b/content/docs/Problemas/distinct.md @@ -3,8 +3,8 @@ weight: 10 title: "Distinct Range Query" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/distinctUpdate.md b/content/docs/Problemas/distinctUpdate.md index 7691a40..0c3deb9 100644 --- a/content/docs/Problemas/distinctUpdate.md +++ b/content/docs/Problemas/distinctUpdate.md @@ -3,8 +3,8 @@ weight: 10 title: "Distinct Range Query com Update" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/dominacao3d.md b/content/docs/Problemas/dominacao3d.md index 110a7b2..2b0470a 100644 --- a/content/docs/Problemas/dominacao3d.md +++ b/content/docs/Problemas/dominacao3d.md @@ -3,8 +3,8 @@ weight: 10 title: "DP de Dominacao 3D" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/dominatorPoints.md b/content/docs/Problemas/dominatorPoints.md index 633541b..15da42a 100644 --- a/content/docs/Problemas/dominatorPoints.md +++ b/content/docs/Problemas/dominatorPoints.md @@ -3,8 +3,8 @@ weight: 10 title: "Dominator Points" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/dynamicHull.md b/content/docs/Problemas/dynamicHull.md index 669fe90..a2c4bf0 100644 --- a/content/docs/Problemas/dynamicHull.md +++ b/content/docs/Problemas/dynamicHull.md @@ -3,8 +3,8 @@ weight: 10 title: "Convex Hull Dinamico" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/graphTriangles.md b/content/docs/Problemas/graphTriangles.md index 8c35a25..e4535f7 100644 --- a/content/docs/Problemas/graphTriangles.md +++ b/content/docs/Problemas/graphTriangles.md @@ -3,8 +3,8 @@ weight: 10 title: "Triangulos em Grafos" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/grayCode.md b/content/docs/Problemas/grayCode.md index 46efb37..6431040 100644 --- a/content/docs/Problemas/grayCode.md +++ b/content/docs/Problemas/grayCode.md @@ -3,8 +3,8 @@ weight: 10 title: "Gray Code" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/halfPlaneIntersection.md b/content/docs/Problemas/halfPlaneIntersection.md index 8e0927a..722f102 100644 --- a/content/docs/Problemas/halfPlaneIntersection.md +++ b/content/docs/Problemas/halfPlaneIntersection.md @@ -3,8 +3,8 @@ weight: 10 title: "Half-plane intersection" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/heapSort.md b/content/docs/Problemas/heapSort.md index 623884f..5bbb2d9 100644 --- a/content/docs/Problemas/heapSort.md +++ b/content/docs/Problemas/heapSort.md @@ -3,8 +3,8 @@ weight: 10 title: "Heap Sort" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/hungarian.md b/content/docs/Problemas/hungarian.md index e004a23..b6a2c35 100644 --- a/content/docs/Problemas/hungarian.md +++ b/content/docs/Problemas/hungarian.md @@ -3,8 +3,8 @@ weight: 10 title: "Hungaro" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/intervalGraphColoring.md b/content/docs/Problemas/intervalGraphColoring.md index 9bb93cb..94c915e 100644 --- a/content/docs/Problemas/intervalGraphColoring.md +++ b/content/docs/Problemas/intervalGraphColoring.md @@ -3,8 +3,8 @@ weight: 10 title: "Coloracao de Grafo de Intervalo" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/intervalGraphIndSet.md b/content/docs/Problemas/intervalGraphIndSet.md index 350e752..6f97267 100644 --- a/content/docs/Problemas/intervalGraphIndSet.md +++ b/content/docs/Problemas/intervalGraphIndSet.md @@ -3,8 +3,8 @@ weight: 10 title: "Conj. Indep. Maximo com Peso em Grafo de Intervalo" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/inversionCount.md b/content/docs/Problemas/inversionCount.md index b31aa36..1181ca2 100644 --- a/content/docs/Problemas/inversionCount.md +++ b/content/docs/Problemas/inversionCount.md @@ -3,8 +3,8 @@ weight: 10 title: "Inversion Count" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/lis.md b/content/docs/Problemas/lis.md index d1d2154..9fc2a2b 100644 --- a/content/docs/Problemas/lis.md +++ b/content/docs/Problemas/lis.md @@ -3,8 +3,8 @@ weight: 10 title: "LIS - recupera" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/lis2.md b/content/docs/Problemas/lis2.md index 1d5e134..b606e9e 100644 --- a/content/docs/Problemas/lis2.md +++ b/content/docs/Problemas/lis2.md @@ -3,8 +3,8 @@ weight: 10 title: "LIS - tamanho" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/maxDist.md b/content/docs/Problemas/maxDist.md index ba11a7f..54aea0c 100644 --- a/content/docs/Problemas/maxDist.md +++ b/content/docs/Problemas/maxDist.md @@ -3,8 +3,8 @@ weight: 10 title: "Distancia maxima entre dois pontos" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/minCirc.md b/content/docs/Problemas/minCirc.md index e590bf3..96c989d 100644 --- a/content/docs/Problemas/minCirc.md +++ b/content/docs/Problemas/minCirc.md @@ -3,8 +3,8 @@ weight: 10 title: "Minimum Enclosing Circle" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/minkowski.md b/content/docs/Problemas/minkowski.md index cd4d3ed..0c9b5f7 100644 --- a/content/docs/Problemas/minkowski.md +++ b/content/docs/Problemas/minkowski.md @@ -3,8 +3,8 @@ weight: 10 title: "Minkowski Sum" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/mo.md b/content/docs/Problemas/mo.md index 48f782d..3d6d07c 100644 --- a/content/docs/Problemas/mo.md +++ b/content/docs/Problemas/mo.md @@ -3,8 +3,8 @@ weight: 10 title: "MO" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/moDsu.md b/content/docs/Problemas/moDsu.md index 06e8822..2552c4e 100644 --- a/content/docs/Problemas/moDsu.md +++ b/content/docs/Problemas/moDsu.md @@ -3,8 +3,8 @@ weight: 10 title: "MO - DSU" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/moOnTrees.md b/content/docs/Problemas/moOnTrees.md index b6c8f64..283fec3 100644 --- a/content/docs/Problemas/moOnTrees.md +++ b/content/docs/Problemas/moOnTrees.md @@ -3,8 +3,8 @@ weight: 10 title: "MO em Arvores" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/palindromicFactorization.md b/content/docs/Problemas/palindromicFactorization.md index be6504b..dac1269 100644 --- a/content/docs/Problemas/palindromicFactorization.md +++ b/content/docs/Problemas/palindromicFactorization.md @@ -3,8 +3,8 @@ weight: 10 title: "Palindromic Factorization" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/parsing.md b/content/docs/Problemas/parsing.md index a569672..6148812 100644 --- a/content/docs/Problemas/parsing.md +++ b/content/docs/Problemas/parsing.md @@ -3,8 +3,8 @@ weight: 10 title: "Parsing de Expressao" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/rmqOffline.md b/content/docs/Problemas/rmqOffline.md index 99a37cb..b6c2540 100644 --- a/content/docs/Problemas/rmqOffline.md +++ b/content/docs/Problemas/rmqOffline.md @@ -3,8 +3,8 @@ weight: 10 title: "RMQ com Divide and Conquer" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/segmentIntersection.md b/content/docs/Problemas/segmentIntersection.md index a08f217..7516afc 100644 --- a/content/docs/Problemas/segmentIntersection.md +++ b/content/docs/Problemas/segmentIntersection.md @@ -3,8 +3,8 @@ weight: 10 title: "Segment Intersection" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/simplePolygon.md b/content/docs/Problemas/simplePolygon.md index b675d01..2ac0299 100644 --- a/content/docs/Problemas/simplePolygon.md +++ b/content/docs/Problemas/simplePolygon.md @@ -3,8 +3,8 @@ weight: 10 title: "Simple Polygon" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/steinerTree.md b/content/docs/Problemas/steinerTree.md index 304780f..6224e2f 100644 --- a/content/docs/Problemas/steinerTree.md +++ b/content/docs/Problemas/steinerTree.md @@ -3,8 +3,8 @@ weight: 10 title: "Steiner Tree" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Problemas/sweepDirection.md b/content/docs/Problemas/sweepDirection.md index 690f095..bf64188 100644 --- a/content/docs/Problemas/sweepDirection.md +++ b/content/docs/Problemas/sweepDirection.md @@ -3,8 +3,8 @@ weight: 10 title: "Sweep Direction" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Strings/_index.md b/content/docs/Strings/_index.md index b4de32b..579bd7b 100644 --- a/content/docs/Strings/_index.md +++ b/content/docs/Strings/_index.md @@ -2,7 +2,7 @@ weight: 10 title: "Strings" draft: false -date: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" description: "" -publishdate: "2024-05-09T17:19:25-0300" +publishdate: "2024-05-09T18:39:18-0300" --- diff --git a/content/docs/Strings/ahocorasick.md b/content/docs/Strings/ahocorasick.md index 782b476..97a23d7 100644 --- a/content/docs/Strings/ahocorasick.md +++ b/content/docs/Strings/ahocorasick.md @@ -3,8 +3,8 @@ weight: 10 title: "Aho-corasick" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Strings/dynamicSuffixArray.md b/content/docs/Strings/dynamicSuffixArray.md index 32ae5ca..a84c79c 100644 --- a/content/docs/Strings/dynamicSuffixArray.md +++ b/content/docs/Strings/dynamicSuffixArray.md @@ -3,8 +3,8 @@ weight: 10 title: "Suffix Array Dinamico" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Strings/eertree.md b/content/docs/Strings/eertree.md index 2c4df27..49d528b 100644 --- a/content/docs/Strings/eertree.md +++ b/content/docs/Strings/eertree.md @@ -3,8 +3,8 @@ weight: 10 title: "eertree" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Strings/hashing.md b/content/docs/Strings/hashing.md index 09c61b8..e8041a2 100644 --- a/content/docs/Strings/hashing.md +++ b/content/docs/Strings/hashing.md @@ -3,8 +3,8 @@ weight: 10 title: "String Hashing" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Strings/hashingLargeMod.md b/content/docs/Strings/hashingLargeMod.md index 6804ff4..06e0bbe 100644 --- a/content/docs/Strings/hashingLargeMod.md +++ b/content/docs/Strings/hashingLargeMod.md @@ -3,8 +3,8 @@ weight: 10 title: "String Hashing - modulo 2^61 - 1" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Strings/kmp.md b/content/docs/Strings/kmp.md index 84bb2e6..6256f0d 100644 --- a/content/docs/Strings/kmp.md +++ b/content/docs/Strings/kmp.md @@ -3,8 +3,8 @@ weight: 10 title: "KMP" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Strings/manacher.md b/content/docs/Strings/manacher.md index 8d59d05..86904dd 100644 --- a/content/docs/Strings/manacher.md +++ b/content/docs/Strings/manacher.md @@ -3,8 +3,8 @@ weight: 10 title: "Manacher" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Strings/minMaxSuffixCyclic.md b/content/docs/Strings/minMaxSuffixCyclic.md index 9e6470f..1afbe17 100644 --- a/content/docs/Strings/minMaxSuffixCyclic.md +++ b/content/docs/Strings/minMaxSuffixCyclic.md @@ -3,8 +3,8 @@ weight: 10 title: "Min/max suffix/cyclic shift" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Strings/suffixArray.md b/content/docs/Strings/suffixArray.md index b682bcb..f2e11f9 100644 --- a/content/docs/Strings/suffixArray.md +++ b/content/docs/Strings/suffixArray.md @@ -3,8 +3,8 @@ weight: 10 title: "Suffix Array - O(n)" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Strings/suffixArray2.md b/content/docs/Strings/suffixArray2.md index 053ecf4..100d4f4 100644 --- a/content/docs/Strings/suffixArray2.md +++ b/content/docs/Strings/suffixArray2.md @@ -3,8 +3,8 @@ weight: 10 title: "Suffix Array - O(n log n)" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Strings/suffixAutomaton.md b/content/docs/Strings/suffixAutomaton.md index a5515de..870679a 100644 --- a/content/docs/Strings/suffixAutomaton.md +++ b/content/docs/Strings/suffixAutomaton.md @@ -3,8 +3,8 @@ weight: 10 title: "Suffix Automaton" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Strings/trie.md b/content/docs/Strings/trie.md index ee0e38f..c8350c9 100644 --- a/content/docs/Strings/trie.md +++ b/content/docs/Strings/trie.md @@ -3,8 +3,8 @@ weight: 10 title: "Trie" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- diff --git a/content/docs/Strings/z.md b/content/docs/Strings/z.md index 5f3b5be..2a379ba 100644 --- a/content/docs/Strings/z.md +++ b/content/docs/Strings/z.md @@ -3,8 +3,8 @@ weight: 10 title: "Z" draft: false toc: true -date: "2024-05-09T17:19:25-0300" -publishdate: "2024-05-09T17:19:25-0300" +date: "2024-05-09T18:39:18-0300" +publishdate: "2024-05-09T18:39:18-0300" description: "" --- From a19592723b49e6f0f6abd7d5d1b9decc48f8a203 Mon Sep 17 00:00:00 2001 From: luizacbcampos Date: Thu, 9 May 2024 20:23:53 -0300 Subject: [PATCH 43/43] this branch will have bruno's site --- hugo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hugo.toml b/hugo.toml index 6bfe212..47de370 100644 --- a/hugo.toml +++ b/hugo.toml @@ -1,4 +1,4 @@ -baseURL = "https://luizacbcampos.github.io/Biblioteca" # (or set via env variable HUGO_BASEURL) +baseURL = "https://brunomaletta.github.io/Biblioteca" # (or set via env variable HUGO_BASEURL) languageCode = "pt-BR" title = "Biblioteca" contentDir = "content"