字典树(小结)

0.1 字典树

功能:

在数组中找与一个数异或值最大的元素。

支持添加,删除操作,查找操作。

 例如:hdu4825

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <map>
#include <set>
#include <ctype.h>
#include <cmath>
#include <queue>
#include <stack>
using namespace std;
typedef long long ll;
const int MAX = 35*1e5+5;
ll a[MAX];
int root,tot,Next[MAX][2],cnt[MAX];
ll End[MAX];
int Newnode()
{
	memset(Next[tot],-1,sizeof(Next[tot]));
	cnt[tot] = 0;
	End[tot] = 0;
	return tot ++;
}

void Init()
{
	tot = 0;
	root = Newnode();
}

void Insert(ll x)
{
	int p = root;
	cnt[p] ++;
	for(int i = 32; i >= 0; i--)
	{
    	int idx = ((1LL<<i)&x) ? 1 : 0;
		if(Next[p][idx]  == -1)
		{
			Next[p][idx] = Newnode();
		}
			p = Next[p][idx];
			cnt[p] ++;
		}
		End[p] = x;
	}

void Del(ll x)
{
	int p = root;
	cnt[p]--;
	for(int i = 32; i>=0 ; i--)
	{
		int idx = ((1LL<<i)&x)?1:0;
		p = Next[p][idx];
		cnt[p]--;
		}
}

ll Search(ll x)
{
	int p = root;
	for(int i = 32; i>=0 ; i--)
	{
    	int idx = ((1LL<<i)&x)?1:0;
		if(idx == 0)
		{
			if(Next[p][1] != -1 && cnt[Next[p][1]])
			    p = Next[p][1];
			else
			    p = Next[p][0];
		}
		else
		{
			if(Next[p][0] != -1 && cnt[Next[p][0]])
			    p = Next[p][0];
			else
			    p = Next[p][1];
		}
	}
	return End[p];
}
int main()
{
    int t;
    scanf("%d",&t);
    int cas = 1;
    while(t--)
    {
    	Init();
    	int n,m,ma = 0;
    	scanf("%d%d",&n,&m);
    	for(int i = 0; i < n; i++)
    	{
    		scanf("%lld",&a[i]);
    		Insert(a[i]);
    	}
    	printf("Case #%d:\n",cas++);
    	while(m--)
    	{
    		ll x;
    		scanf("%lld",&x);
    		int ans = Search(x);
    		printf("%d\n",ans);
    	}
    }
	return 0;
}

单词字典树

输入n个单词,m个查询,求查询的单词是否出现,几次,或者是否以前缀形式出现

数据量小也可用map 解决

如https://qduoj.com/problem/2

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <map>
#include <set>
#include <ctype.h>
#include <cmath>
#include <queue>
#include <stack>
using namespace std;
typedef long long ll;
const int MAX = 100*1e3+5;    // 每个数分32个..

int root,tot,Next[MAX][30],cnt[MAX];
int Newnode()
{
	memset(Next[tot],-1,sizeof(Next[tot]));
	cnt[tot] = 0;
	return tot ++;
}

void Init()
{
	tot = 0;
	root = Newnode();
}

int getid(char ch)
{
	if(ch == '*') return 26;
	if(ch == '?') return 27;
	return ch-'a';
}

int isover(char s[])
{
	for(int i = 0; s[i]; i++)
		if(s[i] != '*') return 0;
	return 1;
}

void Insert(int p,char s[])
{
	if(s[0] == 0)
	{
		cnt[p] = 1;
		return;
	}
	int id = getid(s[0]);
	if(Next[p][id] == -1)
	{
		Next[p][id] = Newnode();
	}
	if(isover(s)) cnt[p] = 1;
	Insert(Next[p][id],s+1);
}

int Search(int p,char s[])
{
	if(s[0] == 0)
	{
		return cnt[p] != 0;
	}
	int id = getid(s[0]);
	if(Next[p][id] != -1)
	{
		if(Search(Next[p][id],s+1)) return 1;
	}
	if(Next[p][27] != -1)
	{
		if(Search(Next[p][27],s+1)) return 1;
	}
	if(Next[p][26] != -1)
	{
		int len = strlen(s);
		for(int i = 0; i <= len; i++)
		{
		    if(Search(Next[p][26],s+i)) return 1;
		}
	}
	return 0;
}
char s[1005];
int main()
{
    int t;
    scanf("%d",&t);
    int cas = 1;
    while(t--)
    {
		int n,m;
		Init();
		scanf("%d%d",&n,&m);
		for(int i = 0;i < n; i++)
		{
			scanf("%s",s);
			Insert(root,s);
		}
		printf("Case #%d:\n",cas++);
		for(int i = 0; i < m ;i++)
		{
			int yes;
			scanf("%s",s);
			yes = Search(root,s);
			printf("%d",yes);
		}
		puts("");
    }
	return 0;
}

再比如hdu2846后缀字典树,查询的是某单词是字典中几个单词的子串,,后缀加排除重复,如果问的是子串出现的·次数,就不用排重

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <map>
#include <set>
#include <ctype.h>
#include <cmath>
#include <queue>
#include <stack>
using namespace std;
typedef long long ll;
const int MAX = 25*1e5+5;   

int root,tot,Next[MAX][30],cnt[MAX],of[MAX];
int Newnode()
{
	memset(Next[tot],-1,sizeof(Next[tot]));
	cnt[tot] = 0;
	of[tot] = 0;
	return tot ++;
}

void Init()
{
	tot = 0;
	root = Newnode();
}

int getid(char ch)
{
	return ch-'a';
}

void Insert(int p,char s[],int cur)
{
	if(s[0] == 0)
	{
		if(of[p] != cur)
	    {
		    cnt[p]++;
		    of[p] = cur;
	    }
		return;
	}
	int id = getid(s[0]);
	if(Next[p][id] == -1)
	{
		Next[p][id] = Newnode();
	}
	if(of[p] != cur)    // 防止字典中的一个单词重复记录某个子串
	{
		cnt[p]++;
		of[p] = cur;
	}
	Insert(Next[p][id],s+1,cur);
}

int Search(int p,char s[])
{
	if(s[0] == 0)
	{
		return cnt[p];
	}
	int id = getid(s[0]);
	if(Next[p][id] != -1)
	{
		return Search(Next[p][id],s+1);
	}
	return 0;
}
char s[1005];
char str[1005];
map <string,bool> mp;
int main()
{
	int n;
	scanf("%d",&n);
	Init();
	for(int i = 1; i <= n; i++)
	{
		scanf("%s",s);
		for(int j = 0; s[j]; j++)
		{
			Insert(root,s+j,i);
		}
	}
	int m;
	scanf("%d",&m);
	while(m--)
	{
		scanf("%s",s);
		printf("%d\n",Search(root,s));
	}
	return 0;
}

hdu 1305 求给定字符串数组某个元素是否是某个其它元素的前缀,,保存所有前缀,查询每个单词,看出现次数是否均为1

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <map>
#include <set>
#include <ctype.h>
#include <cmath>
#include <queue>
#include <stack>
using namespace std;
typedef long long ll;
const int MAX = 25*1e5+5;

int root,tot,Next[MAX][3],cnt[MAX];
int Newnode()
{
	memset(Next[tot],-1,sizeof(Next[tot]));
	cnt[tot] = 0;
	return tot ++;
}

void Init()
{
	tot = 0;
	root = Newnode();
}

int getid(char ch)
{
	return ch-'0';
}

void Insert(int p,char s[])
{
	if(s[0] == 0)
	{
		cnt[p]++;
		return;
	}
	int id = getid(s[0]);
	if(Next[p][id] == -1)
	{
		Next[p][id] = Newnode();
	}
	cnt[p] ++;
	Insert(Next[p][id],s+1);
}

int Search(int p,char s[])
{
	if(s[0] == 0)
	{
		return cnt[p];
	}
	int id = getid(s[0]);
	if(Next[p][id] != -1)
	{
		return Search(Next[p][id],s+1);
	}
	return 0;
}
char s[10005][20];
int main()
{
	int k = 0;
	int cas = 1;
	Init();
	while(scanf("%s",s[k])!=EOF)
	{
		if(!strcmp(s[k],"9"))
		{
			int yes = 1;
			for(int i = 0; i < k; i++)
			{
			//	puts(s[i]);
			///	cout <<Search(root,s[i]) <<endl;
				if(Search(root,s[i]) >= 2)
				{
					yes = 0;
				    break;
				}
			}
			if(yes) printf("Set %d is immediately decodable\n",cas++);
			else printf("Set %d is not immediately decodable\n",cas++);
			Init();
			k = 0;
		}
		else
		{
			Insert(root,s[k++]);
		}
	}
	return 0;
}

HDU1247-Hat’s Words

这个可以先把单词存好,逐个查询,枚举分点,注意一个单词可以有 两个一样的单词组成,,,如  aa   这种情况,如过数组有一个a就可以了.......

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <map>
#include <set>
#include <ctype.h>
#include <cmath>
#include <queue>
#include <stack>
using namespace std;
typedef long long ll;
const int MAX = 25*1e5+5;

int root,tot,Next[MAX][30],cnt[MAX];
int Newnode()
{
	memset(Next[tot],-1,sizeof(Next[tot]));
	cnt[tot] = 0;
	return tot ++;
}

void Init()
{
	tot = 0;
	root = Newnode();
}

int getid(char ch)
{
	return ch-'a';
}

void Insert(int p,char s[])
{
	if(s[0] == 0)
	{
		cnt[p]++;
		return;
	}
	int id = getid(s[0]);
	if(Next[p][id] == -1)
	{
		Next[p][id] = Newnode();
	}
	Insert(Next[p][id],s+1);
}

int Search(int p,char s[])
{
	if(s[0] == 0)
	{
		return cnt[p];
	}
	int id = getid(s[0]);
	if(Next[p][id] != -1)
	{
		return Search(Next[p][id],s+1);
	}
	return 0;
}
char s[50005][500];
char str[500];
int main()
{
	int k = 0;
	Init();
	while(scanf("%s",s[k])!=EOF)
	{
		Insert(root,s[k]);
		k++;
	}
	for(int i = 0; i < k; i++)
	{
		int len = strlen(s[i]);
		for(int j = 0; j < len-1; j++)
		{
			str[j] = s[i][j];
			str[j+1] = 0;
			if(Search(root,str) >= 1 && Search(root,&s[i][j+1]) >= 1)
			{
				puts(s[i]);
				break;
			}
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/sunmoonvocano/article/details/79825811