Trie&可持久化Trie

Trie(字典樹)

#include<bits/stdc++.h>
using namespace std;

const  int N =1000*1000+10;
int n,m,size[N][26],tot=1,endpos[N*2];
char s[N];
void insert(char s[]){
    int len=strlen(s),p=1;
    for(int i=0;i<len;i++){
        int a=s[i]-'a';
        if(size[p][a]==0)size[p][a]=++tot;
        p=size[p][a];
    }
    endpos[p]++;
}

int solve(char s[]){
    int ans=0;
    int len=strlen(s);
    int p=1;
    for(int i=0;i<len;i++){
        int k=s[i]-'a';
        int f=size[p][k];
        if(endpos[f])ans+=endpos[f];
        if(f==0)break;
        p=size[p][k];
    }
    return ans;
}

int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%s",s);
        insert(s);
    }
    for(int i=1;i<=m;i++){
        scanf("%s",s);
        printf("%d\n",solve(s));
    }
    
    return 0;
}

可持久化Trie
保存的是前k個串的信息,如果想要查詢區間[L,R]的信息,可以在節點上增加一個信息,表示當前節點最後一次被哪一個串使用last[],查詢的時候從R開始查詢,每查詢的時候都要滿足last[p]>=L,纔可以走這條路去查詢。

#include<bits/stdc++.h>
using namespace std;

const int N = 3 * 100 * 1000 + 10;
char s[N];
int rt[N], trie[N][26],endpos[N],last[N];
int tot = 1;
int len=0;

void insert(int &now, int pre, int p,int k) {	//當前節點,上次訪問的節點,訪問到第p個字符,第k個字符串
	now = ++tot;
	rt[now] = rt[pre];
	if (p == len) {
		endpos[now] = 1;		//標記字符串的結束節點
		last[now] = k;			//當前節點最後一次被第k個字符串使用
		return; 
	}
	int pos = s[p] - 'a';
	if (pre)for (int i = 0; i < 26; i++)trie[now][i] = trie[pre][i]; //複製兒子節點的所有信息
	insert(trie[now][pos], trie[pre][pos], p + 1,k);	
	for (int i = 0; i < 26; i++)last[now] = max(last[now],last[trie[now][i]]);//更新當前節點最後一次被使用的位置
}

void dfs(int k,int r,vector<char>v) {
	if (endpos[r]) {
		for (int i = 0; i < v.size(); i++)cout << v[i];
		cout << endl;
		return;
	}
	for (int i = 0; i < 26; i++) {
		if (trie[r][i]&&last[trie[r][i]]>=k) {
			//printf("%c",i+'a');
			vector<char> vv = v;
			vv.push_back('a'+i);
			dfs(k,trie[r][i],vv);
		}
	}
}

int main() {
	int cnt = 0;
	while (scanf("%s", s), s[0] != '#') {
		len = strlen(s);
		insert(rt[++cnt], rt[cnt - 1], 0,cnt);
	}
	vector<char>v;
	dfs(2,rt[3],v);
	return 0;
}

變種:01字典樹,一般是解決異或問題,就是對每個數在二進制表示下從最高位開始建樹,查詢的時候儘量往相反方向走。這裏就不給出代碼了,和上面的類似。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章