1. 程式人生 > 實用技巧 >Trie樹

Trie樹

什麼是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