Trie 树

Trie树

定义

\(Trie 是一棵有根树,每个点至多有 |Σ| 个后继边,每条边上有一个字符。\)
\(每个点表示一个前缀:从跟到这个点的边上的字符顺次连接形成的字符串。\)
\(每个点还有一个终止标记:是否这个点代表的字符串是一个字典串。\)
\(可以支持向 Trie 插入新字典串,删除字典串,查询某字符串是否是字典串,以及一些稍微复杂的查询。\)
\(作为一个数据结构,它理所应当的还可以进行持久化。\)

模板

普通Trie树

字典树

struct Trie{
    int tot,ch[maxn][27],biao[maxn];
    void insert(string s){
        int u=0,lenth=s.length();
        for(int i=0;i<lenth;i++){
            int k=s[i]-'a';
            if(!ch[u][k])ch[u][k]=++tot;
            u=ch[u][k];
        }
        biao[u]++;
        return;
    }
};

01Trie树

struct Trie{
    int tot,ch[maxn][2],biao[maxn];
    void insert(int x){
        int u=0;
        for(int i=30;i>=0;i--){
            int k=(x>>i)&1;
            if(!ch[u][k])ch[u][k]=++tot;
            u=ch[u][k];
        }
        biao[u]++;
        return;
    }
    int find(int x){		//找异或最大值 
        int u=0,ans=0;
        for(int i=30;i>=0;i--){
            int k=(x>>i)&1;
            if(ch[u][k^1])u=ch[u][k^1],k=1;
            else u=ch[u][k],k=0;
            ans+=k*(1<<i);
        }
        return ans;
    }
}T;

可持久化Trie树

int rt[maxn]; 
struct Trie{
	int tot;
	int ch[maxn][2],cnt[maxn];
	void insert(int now,int pre,int v){
		for(int i=25;i>=0;i--){
			int k=(v>>i)&1;
			ch[now][k^1]=ch[pre][k^1];
			ch[now][k]=++tot;
			cnt[ch[now][k]]=cnt[ch[pre][k]]+1;
			now=ch[now][k];pre=ch[pre][k];
		}
		return ;
	}
	
	int query(int now,int pre,int v){
		int ans=0;
		for(int i=25;i>=0;i--){
			int k=(v>>i)&1;
			if(cnt[ch[now][k^1]]-cnt[ch[pre][k^1]]){
				now=ch[now][k^1];pre=ch[pre][k^1];
				ans+=(1<<i);
			}
			else now=ch[now][k],pre=ch[pre][k];
		}
		return ans;
	}	
}T;

int main(){
    //增加个新节点
    rt[1]=++T.tot;
    T.insert(rt[1],rt[0],0);		//注意这里 
}

例题

1.The XOR Largest Pair

点击查看代码
#include <bits/stdc++.h>
#define ll long long
#define pa pair<int,int>
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define YES {puts("YES");return;}
#define NO {puts("NO");return ;}
using namespace std;
const int maxn=1e6+101;
const int MOD=998244353;
const int inf=2147483647;
const double pi=acos(-1);
const double eps=1e-8;

ll read(){
    ll x=0,f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
    return x*f;
}
struct Trie{
	int tot,ch[maxn][2],biao[maxn];
	void insert(int x){
		int u=0;
		for(int i=30;i>=0;i--){
			int k=(x>>i)&1;
			if(!ch[u][k])ch[u][k]=++tot;
			u=ch[u][k];
		}
		biao[u]++;
		return;
	}
	
	int find(int x){
		int u=0,ans=0;
		for(int i=30;i>=0;i--){
			int k=(x>>i)&1;
			if(ch[u][k^1])u=ch[u][k^1],k=1;
			else u=ch[u][k],k=0;
			ans+=k*(1<<i);
		}
		return ans;
	}
}T;
int n,a[maxn],ans;
int main(){
	n=read();
	for(int i=1;i<=n;i++){
		a[i]=read();T.insert(a[i]); 
	}
	for(int i=1;i<=n;i++)ans=max(ans,T.find(a[i]));
	printf("%d\n",ans);
    return 0;
}

2.假的字符串
先构建出字典树,然后逐个字符串判定可行性。
考虑 \(S_i\) 在字典树上的每个节点,如果有多于一个后继边,则 \(S_i\) 使用的字母必须小于其他字母。
等价于判定 \(26\) 个点的有向图上是否有环(拓扑排序)。
额外需要注意不能有任何其他串等于 \(S_i\) 的前缀,即路径上不能有其他串的的终止节点。

点击查看代码
#include <bits/stdc++.h>
#define ll long long
#define pa pair<int,int>
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define YES {puts("YES");return;}
#define NO {puts("NO");return ;}
using namespace std;
const int maxn=1e6+101;
const int MOD=998244353;
const int inf=2147483647;
const double pi=acos(-1);
const double eps=1e-8;

ll read(){
    ll x=0,f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
    return x*f;
}
struct Trie{
	int tot,ch[maxn][27],biao[maxn];
	void insert(string s){
		int u=0,lenth=s.length();
		for(int i=0;i<lenth;i++){
			int k=s[i]-'a';
			if(!ch[u][k])ch[u][k]=++tot;
			u=ch[u][k];
		}
		biao[u]++;
		return;
	}
	int in[27],ed[26][26];
	int get_ans(string s){
		memset(ed,0,sizeof(ed));
		memset(in,0,sizeof(in));
		int u=0,lenth=s.length();
		for(int i=0;i<lenth;i++){
			if(biao[u])return 0;
			int k=s[i]-'a';
			for(int j=0;j<26;j++){
				if(j==k || !ch[u][j] || ed[k][j])continue;
				ed[k][j]=1;
				in[j]++;
			}
			u=ch[u][k];
			
		}
		queue<int>q;
		for(int i=0;i<26;i++)if(!in[i])q.push(i);
		while(!q.empty()){
			int u=q.front();q.pop();
			for(int j=0;j<26;j++){
				if(ed[u][j]){
					in[j]--;
					if(!in[j])q.push(j);
				}
			}
		}
		for(int i=0;i<26;i++)if(in[i])return 0;
		return 1;
	}
}T;
int n; 
string a[30001];
int main(){
	n=read();
	for(int i=1;i<=n;i++){cin>>a[i];T.insert(a[i]);}
	vector<string>ans;
	for(int i=1;i<=n;i++){
		if(T.get_ans(a[i]))ans.pb(a[i]);
	}
	printf("%d\n",(int)ans.size());
	for(auto i:ans)cout<<i<<endl;
    return 0;

}

3.最大异或和

点击查看代码
#include <bits/stdc++.h>
#define ll long long
#define pa pair<int,int>
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define YES {puts("YES");return;}
#define NO {puts("NO");return ;}
using namespace std;
const int maxn=2e7+101;
const int MOD=998244353;
const int inf=2147483647;
const double pi=acos(-1);
const double eps=1e-8;

ll read(){
    ll x=0,f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
    return x*f;
}
int rt[maxn]; 
struct Trie{
	int tot;
	int ch[maxn][2],cnt[maxn];
	void insert(int now,int pre,int v){
		for(int i=25;i>=0;i--){
			int k=(v>>i)&1;
			ch[now][k^1]=ch[pre][k^1];
			ch[now][k]=++tot;
			cnt[ch[now][k]]=cnt[ch[pre][k]]+1;
			now=ch[now][k];pre=ch[pre][k];
		}
		return ;
	}
	
	int query(int now,int pre,int v){
		int ans=0;
		for(int i=25;i>=0;i--){
			int k=(v>>i)&1;
			if(cnt[ch[now][k^1]]-cnt[ch[pre][k^1]]){
				now=ch[now][k^1];pre=ch[pre][k^1];
				ans+=(1<<i);
			}
			else now=ch[now][k],pre=ch[pre][k];
		}
		return ans;
	}	
}T;
int n,m,sum;
int main(){
	n=read();m=read();
	rt[1]=++T.tot;
	T.insert(rt[1],rt[0],0);		//注意这里 
	n++;
	for(int i=2;i<=n;i++){
		sum^=read();rt[i]=++T.tot;
		T.insert(rt[i],rt[i-1],sum);
	}
	while(m--){
		char ch[2];cin>>ch[0];
		if(ch[0]=='A'){
			int x=read();sum^=x;n++;rt[n]=++T.tot;
			T.insert(rt[n],rt[n-1],sum);
		}
		else {
			int l=read(),r=read(),x=read();
			int now=sum^x;
			cout<<T.query(rt[r],rt[l-1],now)<<endl;
		}
	}
    return 0;

}
posted @ 2022-10-06 15:09  I_N_V  阅读(27)  评论(0编辑  收藏  举报