Trie樹
阿新 • • 發佈:2020-08-23
什麼是Trie
我們現在有很多很多的單詞,想要記錄下來並對它們進行各種神奇的操作(比如求最長字首以及字串匹配什麼的),這時候我們就要用\(trie\)來記錄。
煮個栗子:
我們現在要記錄下\(qwqwqwq\) ,\(qwqwqaq\) ,\(qqqqq\)這三個單詞,建出來的\(trie\)就長這樣
顯然這棵\(trie\)要支援插入,那麼怎麼插入呢?
插入操作
在上面的\(qwqwqwq\)和\(qwqwqaq\)中可以看出來它們共用了\(qwqwq\)這個部分。新插入字串也是如此。從根開始遍歷,不斷尋找當前點中和下一個要插入的字元相同的兒子,如果沒有就新建。然後跳到這個兒子上,重複此過程。插入完所有字元後,在當前所在的點打上結尾標記(就像上圖中藍色的那樣)
在寫程式碼的時候,用\(ch[i][j]\)表示節點編號為\(i\),表示的字元為\(j\)的子節點的編號
程式碼:
void add()//這裡已經在主函式裡輸入當前要插入的字串ms { int len=strlen(ms); int now=1; for(int i=0;i<len;i++)//挨個字元插入 { int ch=ms[i]-'a'; if(!trie[now][ch]) trie[now][ch]=++cnt;//找不到就新建 now=trie[now][ch];//尋找表示字元相同的子節點 } en[now]++;//en[i]記錄以i節點為結尾的字串的個數 }
關於查詢因題而異
板子題
Trie的一些應用
1.字串排序
直接從左到右遍歷就好了
2.詞頻統計
找一下最大的\(en[i]\)
3.\(AC\)自動機(\(NOIP\)不考)
\(trie\)上\(kmp\)
4.求給出的所有串中某個字首的出現次數
01 Trie
顧名思義,01 \(trie\)上的點代表的字元只有0和1,插入的方式和上面的是一樣的。
這個東西在處理異或問題時十分管用。
煮個栗子
假設現在給你\(n\)個數,這\(n\)個數兩兩異或,求最大的異或值。
暴力\(O(n^2)\)。
考慮一個數與其他數的最大異或值,可以採用貪心的思想每次都走與這個數當前位相反的(如果沒有就只能走相同的了)。
不過這玩意大概是省選才會考的
今年\(Day 2\ T2\)就是對樹進行操作再加\(01\ trie\)
插入:
insert(int x){
int now=0;
for(int i=31;i>=0;i--)
{
int v=(x&(1<<i))>>i;
if(!ch[now][v]){
ch[now][v]=++cnt;
}
now=ch[now][v];
}
en[now]++;
}
板子題:最大異或路徑
某鴿子咕咕咕了好久.jpg