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字典树,一般是解决异或问题,就是对每个数在二进制表示下从最高位开始建树,查询的时候尽量往相反方向走。这里就不给出代码了,和上面的类似。

发布了70 篇原创文章 · 获赞 5 · 访问量 7172

猜你喜欢

转载自blog.csdn.net/xiaonanxinyi/article/details/99701562