01Trie學習筆記


前置知識:

Trie樹

百度百科

xor的一些性質

  • \(xor\)對於\(0\)\(1\),兩個數相同返回\(0\),不同返回\(1\)

所以我們可以得到一些很有意思的結論

  1. \[0\ xor\ 1\ =\ 1 \]

  2. \[1\ xor\ 1\ =\ 0 \]

  3. \[p\ xor\ p\ =\ 0 \]

  4. \[p\ xor\ 0\ =\ p \]

根據第\(1\)\(2\)條我們可以用\(xor\ 1\)來實現\(0\rightarrow 1\)\(1\rightarrow 0\)的操作

  • 自反性

\[a\ xor\ b\ =\ c \]

\[c\ xor\ b\ = \ a \]

and的一些性質

  • \(and\)對於\(0\)\(1\),只有兩個數都是\(1\)返回\(1\),其余返回\(0\)

原理

相信大家都知道\(Trie\)樹,\(01Trie\)其實就是對數的二進制位進行建\(Trie\)樹,它被用來處理一些和\(xor\)有關的問題。

首先是建樹部分就是每一個要插入的數轉化為二進制的\(01\)串,然后按從低位或從高位建樹(取決於題目),注意\(01Trie\)的信息是存在節點上的但實際是存在邊上的。

從高位建樹

		int rt=0;
		for (int i=maxsize;i;i>>=1)
		{
			bool x=val&i; 
			if (!ch[rt][x]) ch[rt][x]=++cnt;
			rt=ch[rt][x];
		}

其中\(maxsize\)是大於最大數的\(2^n\),這樣就相當於每次都將一個\(1\)往低位移動,然后根據\(and\)的性質就可以判斷這一位是\(0\)還是\(1\)

例題

P4551 最長異或路徑

題目鏈接

這道題目,只需要從根節點把到每個點的異或和都求一下,然后再在這些數中找兩個異或起來最大的數就可以了。

為什么呢??

根據異或的性質,在\(LCA\)以上邊權會抵消不會影響答案。

然后我們從高位開始貪心,因為高位的一個\(1\)顯然比低位的優。

怎樣貪心呢??

我們想盡量讓它返回\(1\),所以我們只需要判斷是否有當前位異或\(1\)的節點就可以了。

#include<iostream>
#include<cstdio>
using namespace std;
const int N=1e5+100,maxsize=1<<30;
struct edge{
	int s,e,v,net;
}ed[N<<1];
int cnt;
struct Tire{
	int ch[N<<5][2];
	inline void add(int val)
	{
		int rt=0;
		for (int i=maxsize;i;i>>=1)
		{
			bool x=val&i;
			if (!ch[rt][x]) ch[rt][x]=++cnt;
			rt=ch[rt][x];
		}
	}
	inline int query(int val)
	{
		int ans=0,rt=0;
		for (int i=maxsize;i;i>>=1)
		{
			bool x=val&i;
			if (ch[rt][x^1])
			{
				ans=(ans<<1)|(x^1);
				rt=ch[rt][x^1];
			}
			else
			{
				ans=(ans<<1)|x;
				rt=ch[rt][x];
			}
		}
		return ans;
	}
}T; 
int n,tot;
int head[N],val[N];
inline void dfs(int x,int fa)
{
	for (int i=head[x];i;i=ed[i].net)
	if (ed[i].e!=fa)
	{
		val[ed[i].e]=val[x]^ed[i].v;
		dfs(ed[i].e,x);
	}
	return ;
}
inline void add(int s,int e,int v)
{
	ed[++tot]=(edge){s,e,v,head[s]};
	head[s]=tot;
	return ;
}
int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n-1;i++)
	{
		int s,e,v;
		scanf("%d%d%d",&s,&e,&v);
		add(s,e,v);add(e,s,v);
	}
	dfs(1,0);
	for (int i=1;i<=n;i++)
	T.add(val[i]);
	int maxx=0;
	for (int i=1;i<=n;i++)
	maxx=max(T.query(val[i])^val[i],maxx);      //因為01Tire求的是讓這個數異或的最大值的異或值,所以還要異或回來
	printf("%d\n",maxx);
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM