數據結構·字典樹

字典樹trie

顧名思義,在一個字符串的集合查詢某個字符串是否存在樹形結構
樹存儲方式上用的是結構體數組,類似滿二叉樹的形式。

模板

定義結構體和trie

  • 結構體必須的內容:當前結點的字符,孩子數組
  • 可選:end用于查詢,repeat用于統計。
typedef struct node {char c;int children[30] = {0};int end = 0, repeat = 0;
};
vector<node>trie;
node root;
trie.push_back(root);

建樹三部曲

  • 不好理解的可能就是這個fa,用于表示當前的父節點是誰
  • 查詢結點是否存在于父節點的孩子中:if (!trie[fa].children[idx])
  • 沒有存在則添加結點:創建新下標int new_idx = trie.size(),父節點的孩子添加該下標。

			int new_idx = trie.size();trie[fa].children[idx] = new_idx;node x;x.c = s[i];if (i == s.size() - 1) {x.end = 1;}trie.push_back(x);
  • 父節點變為子節點:fa = trie[fa].children[idx]
void build(string s) {int fa = 0;for (int i = 0; i < s.size(); i++) {int idx = s[i] - 'a';if (!trie[fa].children[idx]) {int new_idx = trie.size();trie[fa].children[idx] = new_idx;node x;x.c = s[i];if (i == s.size() - 1) {x.end = 1;}trie.push_back(x);fa = new_idx;}else {if (i == s.size() - 1) {trie[fa].end = 1;}fa = trie[fa].children[idx];}}
}

字符串的查詢

  • 從父親結點一直遍歷到葉子結點,最后i==s.size()-1時特判end是否為end==true?即可
  • 與建樹過程幾乎完全一致
void query(string s) {int fa = 0;for (int i = 0; i < s.size(); i++) {int idx = s[i] - 'a';if (!trie[fa].children[idx]) {cout << "WRONG" << endl;return;}else {fa = trie[fa].children[idx];if (i == s.size() - 1) {if (trie[fa].repeat) {cout << "REPEAT" << endl;}else {if (trie[fa].end) {trie[fa].repeat = 1;cout << "OK" << endl;}else cout << "WRONG" << endl;}}}}
}

打印字典樹

void print_trie() {for (int i = 0; i < trie.size(); i++) {cout << trie[i].c << "|";for (int j = 0; j < 30; j++) {if (trie[i].children[j])cout << trie[i].children[j] << " ";}cout << "|" << trie[i].end << "|" << trie[i].repeat<<endl;}
}

應用

  • P2580 于是他錯誤的點名開始了:標準的查詢字符串操作。

0-1字典樹

  • 將數字用二進制形式保存在trie中,一般是高位到低位。配合貪心思想,可以節約查詢操作

  • P4551 最長異或路徑:這里需要用的異或的自反性質:自己跟自己異或不影響計算。當i<j, [ 1 , i ] ⊕ [ 1 , j ] = [ i , j ] [1,i] \oplus [1,j]=[i,j] [1,i][1,j]=[i,j], [ i , j ] [i,j] [i,j]表示i到j的異或路徑。現在這個問題就變成了先獲得[1,i],然后再遍歷每個j,計算 [ 1 , i ] ⊕ [ 1 , j ] [1,i] \oplus [1,j] [1,i][1,j]的最大值。時間復雜度為平方。將這些[1,i]結果保存為字典樹,然后利用貪心從高位到低位選擇最大的異或結果即可

  • 注意bitset<int>val這個庫,接受字符串和整型作為構造函數。一定要注意的是遍歷時:從低位到高位遍歷,val[0]表示從右往左第一位(也就是低位)for (int i = bitval.size() - 1; i >= 0; i--)

#include<bits/stdc++.h>
#define MAX_VALUE 1000009
#define mod 1000007
using ll = long long;
using namespace std;
typedef struct node {int x, w;node(int a, int b) :x(a), w(b) {};
};
typedef struct trie_node {int val, children[2] = { 0 };
};
vector<list<node>>graph(100009, list<node>());
int n, u, v, w, xors[100009], ans = INT_MIN;
vector<trie_node>trie;
void dfs(int st, int val) {xors[st] = val;for (auto item : graph[st]) {dfs(item.x, val ^ item.w);}
}
void build(int val) {int fa = 0;bitset<32>bitval(val);//bitset[0]是指第一位for (int i = bitval.size() - 1; i >= 0; i--) {//cout << "val:"<<val<<" i:"<<i<<" bitval[i]:" << bitval[i] << endl;if (!trie[fa].children[bitval[i]]) {int new_idx = trie.size();trie[fa].children[bitval[i]] = new_idx;trie_node x;x.val = bitval[i];trie.push_back(x);fa = new_idx;}else {fa = trie[fa].children[bitval[i]];}}
}
int query(int val) {int fa = 0;bitset<32>bitval(val);//二進制bitset<32>res;//bitset[0]是指第一位for (int i = bitval.size() - 1; i >= 0; i--) {if (trie[fa].children[!bitval[i]]) {//取反fa = trie[fa].children[!bitval[i]];res[i] = 1;}else {fa = trie[fa].children[bitval[i]];res[i] = 0;}}return (int)res.to_ulong();
}
void printout() {for (int i = 0; i < trie.size(); i++) {cout << trie[i].val << "|";for (int j = 0; j < 2; j++) {if (trie[i].children[j])cout << trie[i].children[j] << " ";}cout << "|" << endl;}
}
void solve() {cin >> n;for (int i = 1; i < n; i++) {cin >> u >> v >> w;graph[u].push_back(node(v, w));}dfs(1, 0);//for (int i = 1; i <= n; i++) {//	cout << xors[i] << " ";//}//cout << endl;trie_node root;trie.push_back(root);for (int i = 1; i <= n; i++) {build(xors[i]);}//printout();for (int i = 1; i <= n; i++) {ans = max(ans, query(xors[i]));}cout << ans;}
int main() {std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);solve();return 0;
}
  • P6824 「EZEC-4」可樂:這里x是有最大值的,暴力方法是對于每一個x都進行異或看看是否滿足條件,時間復雜度為平方。利用a[i]構造0-1trie,可以在位級別,加速判斷。對于第i位,如果k[i]為1,只需要找到與x[i]相同數字的結點,就一定可以知道x與該結點下的a[i]滿足條件。如果k[i]=0,需要找到與x[i]相同數字的結點,否則一定不能與該父節點下的a[i]滿足條件,提前結束。這里也是用由高位到低位的貪心思想
#include<bits/stdc++.h>
#define MAX_VALUE 1000009
#define mod 1000007
using ll = long long;
using namespace std;
int n, k, a[1000009],res=INT_MIN;
typedef struct node {int val, children[2] = {0}, repeat = 1;
};
vector<node>trie;
void build(int val) {bitset<32>bitval(val);int fa = 0;for (int i = bitval.size() - 1; i >= 0; i--) {if (!trie[fa].children[bitval[i]]) {int new_idx = trie.size();trie[fa].children[bitval[i]] = new_idx;node x;x.val = bitval[i];trie.push_back(x);fa = new_idx;}else {int idx = trie[fa].children[bitval[i]];fa = idx;trie[idx].repeat++;}}
}
void printout() {for (int i = 0; i < trie.size(); i++) {cout << trie[i].val << "|";for (int j = 0; j < 2; j++) {if(trie[i].children[j])cout << trie[i].children[j] << " ";}cout << "|" << trie[i].repeat << endl;}
}
int query(int val,int k) {int ans = 0;bitset<32>bitval(val);bitset<32>bitk(k);int fa = 0;for (int i = bitval.size() - 1; i >= 0; i--) {if (bitk[i]) {//bitk[i]==1if (trie[fa].children[bitval[i]]) {//xor can be 0int idx = trie[fa].children[bitval[i]];//cout << bitval[i] << " "<<trie[idx].repeat << endl;ans += trie[idx].repeat;}if (trie[fa].children[!bitval[i]]) {fa = trie[fa].children[!bitval[i]];}else {break;}}else {//bitk[i]==0if (trie[fa].children[bitval[i]]) {fa = trie[fa].children[bitval[i]];if (i == 0) {ans += 1;//最后一個結點//cout << "end:" << 1 << endl;}}else break;}}return ans;
}
void solve() {node root;trie.push_back(root);cin >> n >> k;for (int i = 1; i <= n; i++) {cin >> a[i];build(a[i]);}//printout();for (int i = 0; i <= (1<<20); i++) {res = max(res, query(i, k));}cout << res;//cout<<query(0, k);
}int main() {std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);solve();return 0;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/80987.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/80987.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/80987.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

ES面試題系列「一」

1、Elasticsearch 是什么&#xff1f;它與傳統數據庫有什么區別&#xff1f; 答案&#xff1a;Elasticsearch 是一個基于 Lucene 的分布式、開源的搜索和分析引擎&#xff0c;主要用于處理大量的文本數據&#xff0c;提供快速的搜索和分析功能。與傳統數據庫相比&#xff0c;E…

2025年6月一區SCI-不實野燕麥優化算法Animated Oat Optimization-附Matlab免費代碼

引言 近年來&#xff0c;在合理框架內求解優化問題的元啟發式算法的發展引起了全球科學界的極大關注。本期介紹一種新的元啟發式算法——不實野燕麥優化算法Animated Oat Optimization algorithm&#xff0c;AOO。該算法模擬了不實野燕麥的3種獨特行為&#xff0c;于2025年6月…

Agent Builder API - Agent Smith 擴展的后端服務(開源代碼)

?一、軟件介紹 文末提供程序和源碼下載 Agent Builder API - Agent Smith 擴展的后端服務&#xff08;開源代碼&#xff09;手動設置&#xff1a;在本地計算機中克隆此存儲庫并啟動 python FAST API 服務器。&#xff08;可選&#xff09;安裝并設置 Mongo DB。Dev Container…

C及C++的SOAP協議庫

一.gSOAP gSOAP 是一個功能強大的開源工具包&#xff0c;專為 C 和 C 設計&#xff0c;用于快速開發基于 SOAP 協議的 Web 服務和客戶端。 1.協議支持 SOAP 版本&#xff1a;完整支持 SOAP 1.1/1.2 規范&#xff0c;包括消息格式、編碼規則和錯誤處理。 傳輸協議&#xff1a…

html5+css3實現傅里葉變換的動態展示效果(僅供參考)

<!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>傅里葉變換的動態展示效果</title><sty…

ECharts中Map(地圖)樣式配置、漸變色生成

前言 在日常開發中&#xff0c;ECharts 幾乎成了我們繪制數據圖表的標配工具&#xff0c;功能強大到幾乎無所不能。不過每次用的時候都要翻官方文檔查配置項&#xff0c;確實有點小繁瑣 &#x1f605; 為了提升效率&#xff0c;也方便以后快速復用&#xff0c;這里就整理記錄…

內存分配器ptmalloc2、tcmalloc、jemalloc,結構設計、內存分配過程詳解

1. 引言 博主之前做過一個高并發內存池的項目實踐&#xff0c;在實踐中對于內存分配器的內存分配過程理解更加深刻了。在此期間&#xff0c;翻查了不少資料以及博客&#xff0c;發現源碼分享的博客不多&#xff0c;能生動完整的講述ptmalloc2、tcmalloc、jemalloc它們的結構設…

【擁抱AI】Deer-Flow字節跳動開源的多智能體深度研究框架

最近發現一款可以對標甚至可能超越GPT-Researcher的AI深度研究應用&#xff0c;Deer-Flow&#xff08;Deep Exploration and Efficient Research Flow&#xff09;作為字節跳動近期開源的重量級項目&#xff0c;正以其模塊化、靈活性和人機協同能力引發廣泛關注。該項目基于 La…

openfeign與dubbo調用下載excel實踐

一、前言 openfeign和dubbo均是rpc框架 RPC&#xff08;Remote Procedure Call&#xff0c;遠程過程調用&#xff09;框架 是一種允許程序像調用本地方法一樣調用遠程服務器上函數的技術。它隱藏了底層網絡通信的復雜性&#xff0c;讓開發者可以專注于業務邏輯&#xff0c;實現…

解密企業級大模型智能體Agentic AI 關鍵技術:MCP、A2A、Reasoning LLMs-強化學習算法

解密企業級大模型智能體Agentic AI 關鍵技術&#xff1a;MCP、A2A、Reasoning LLMs-強化學習算法 現在我們的核心問題是有一些同學會知道要才能強化學習。為什么才能強化學習&#xff1f;是實現AGI。例如從這個其實你從第一階段開始以后&#xff0c;就是chatbot&#xff0c;這…

音頻分類的學習

1.深度學習PyTorch入門-語音分類 https://blog.csdn.net/sinat_41787040/article/details/129795496 https://github.com/musikalkemist/pytorchforaudio https://github1s.com/musikalkemist/pytorchforaudio/blob/main/04%20Creating%20a%20custom%20dataset/urbansoundda…

美SEC主席:探索比特幣上市證券交易所

作者/演講者&#xff1a;美SEC主席Paul S. Atkins 編譯&#xff1a;Liam 5月12日&#xff0c;由美國SEC加密貨幣特別工作組發起的主題為《資產上鏈&#xff1a;TradFi與DeFi的交匯點》系列圓桌會議如期舉行。 會議期間&#xff0c;現任美SEC主席Paul S. Atkins發表了主旨演講。…

Qt file文件操作詳解

1.引言 很多應用程序都具備操作文件的能力&#xff0c;包括對文件進行寫入和讀取&#xff0c;創建和刪除文件等等&#xff0c;甚至某些應用程序的就是為了操作文件&#xff0c;像WPS Office。基于此Qt框架中專門提供了對文件操作的類&#xff1a;QFile。 2.QFile文件操作 QF…

【測試開發知識儲備】之Jacoco(Java Code Coverage)

文章目錄 Jacoco是什么Jacoco的主要功能&#xff08;一&#xff09;多樣化覆蓋率指標分析&#xff08;二&#xff09; 豐富的報告生成&#xff08;三&#xff09;實時數據收集 Jacoco的工作原理&#xff08;一&#xff09;字節碼增強&#xff08;二&#xff09;測試執行與數據收…

Docker 介紹與使用

Docker 文章目錄 Docker介紹與虛擬機的比較啟動速度占用資源 優勢更容易遷移更容易維護更容易擴展 使用場景持續集成提供可伸縮的云服務搭建微服務架構 鏡像與容器鏡像構成&#xff08;分層結構&#xff09;鏡像與容器的區別 安裝 Docker常用命令介紹鏡像相關容器相關 實戰&…

《AI大模型應知應會100篇》第62篇:TypeChat——類型安全的大模型編程框架

第62篇&#xff1a;TypeChat——類型安全的大模型編程框架 摘要 在構建 AI 應用時&#xff0c;一個常見的痛點是大語言模型&#xff08;LLM&#xff09;輸出的不確定性與格式不一致問題。開發者往往需要手動解析、校驗和處理模型返回的內容&#xff0c;這不僅增加了開發成本&a…

upload-labs通關筆記-第5關 文件上傳之.ini繞過

目錄 一、ini文件繞過原理 二、源碼審計 三、滲透實戰 1、查看提示 2、制作.user.ini文件 &#xff08;1&#xff09;首先創建一個文本文件 &#xff08;2&#xff09;保存文件名為.user.ini 2、制作jpg后綴腳本 &#xff08;1&#xff09;創建一個文本文件 &#xf…

為什么 Linux 上默認沒有 host.docker.internal

在 Linux 環境中&#xff0c;host.docker.internal 是 Docker 為容器提供的一個特殊 DNS 名稱&#xff0c;用于指向宿主機的 IP 地址&#xff08;類似 macOS/Windows 中的行為&#xff09;。但這個功能在 Linux 上默認不啟用&#xff0c;需要手動配置才能使用。以下是詳細解釋和…

C++GO語言微服務和服務發現②

01 創建go-micro項目-查看生成的 proto文件 02 創建go-micro項目-查看生成的main文件和handler ## 創建 micro 服務 命令&#xff1a;micro new --type srv test66 框架默認自帶服務發現&#xff1a;mdns。 使用consul服務發現&#xff1a; 1. 初始consul服務發現&…

Redis--常見數據類型List列表

目錄 一、概念 二、命令 2.1 LPUSH 2.2 LPUSHX 2.3 RPUSH 2.4 RPUSHX 2.5 LRANGE 2.6 LPOP 2.7 RPOP 2.8 LINDEX 2.9 LINSERT 2.10 LLEN 2.11 阻塞版本命令 三、內部編碼 一、概念 列表類型是用來存儲多個有序的字符串&#xff0c;列表中的每個字符串稱為元素&…