字典树&&01字典树专题&&对字典树的理解

对于字典树和01字典树的一点理解:

首先,字典树建树的过程就是按照每个数的前缀来的,如果你要存储一个全小写字母字符串,那么这个树每一个节点最多26个节点,这样的话,如果要找特定的单词的话,按照建树的方式找就可以了。

然后是01字典树,这个树在处理一些异或问题的时候特别好用,首先在存储一个树的过程中,我们是按照从高位开始的,如果是对于int型的,我们就从这个数的32位开始存储,不够的话,按照0补,这是建树的过程。再就是查询的时候,对于给定的数,我们先去找这一位上和他不同的,比如说,如果当前这个数的第i位上是1,那我们就找有没有一个数第i位上是0,如果没有的话,再去找第i位是0的数,然后按照从高位到低位寻找的话,就一定能寻找到满足情况的最优解。

入门:

题目链接:http://acm.sdut.edu.cn/onlinejudge2/index.php/Home/Index/problemdetail/pid/2828.html

用数组模拟。

我的理解:假设给你n个字符串,我们可以把有相同前缀的按照树的形式存储下来,这样就能够节省很多的空间,然后通过递归的形式来建树或者查找子串是否存在或者存在的次数。

AC代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn = 1e6+10;
 4 char tmp[maxn];
 5 int root[maxn][30];
 6 int top;
 7 void init()
 8 {
 9     for(int i=0; i<top; i++)
10     {
11         for(int j=0; j<30; j++)
12         {
13             root[i][j]=0;
14         }
15     }
16     top=0;
17 }
18 void add(char *str)
19 {
20     int tot=0;
21     int len=strlen(str);
22     for(int i=0; i<len; i++)
23     {
24         int t=str[i]-'a';
25         if(root[tot][t]==0)
26             root[tot][t]=++top;
27         tot=root[tot][t];
28     }
29 }
30 bool judge(char *str)
31 {
32     int len=strlen(str);
33     int tot=0;
34     for(int i=0; i<len; i++)
35     {
36         int t=str[i]-'a';
37         if(root[tot][t]==0)
38             return false;
39         tot=root[tot][t];
40     }
41     return true;
42 }
43 int main()
44 {
45     int n,m;
46     top=0;
47     while(~scanf("%d %d",&n,&m)&&(n+m))
48     {
49         init();
50         for(int i=1; i<=n; i++)
51         {
52            // getchar();
53             scanf("%s",tmp);
54             add(tmp);
55            // cout<<tmp<<endl;
56         }
57         for(int i=1; i<=m; i++)
58         {
59           //  getchar();
60             scanf("%s",tmp);
61             if(judge(tmp))
62                 printf("Yes\n");
63             else
64                 printf("No\n");
65         }
66     }
67     return 0;
68 }

 

A题:

题目链接:https://cn.vjudge.net/contest/276901#problem/A

题目大意:先输入若干个字符串,然后再每一次输入一个字符串,问你当前这个字符串再一开始输入的字符串中是前缀的有多少个?

AC代码:

 1 #include<iostream>
 2 #include<stack>
 3 #include<string>
 4 #include<cstring>
 5 #include<stdio.h>
 6 using namespace std;
 7 # define ll long long
 8 const int maxn = 2e6+100;
 9 int rec[maxn][30];
10 int flag[maxn];
11 int tot;
12 char str1[maxn];
13 void add(char *str)
14 {
15     int root=0;
16     int len=strlen(str);
17     for(int i=0; i<len; i++)
18     {
19         int t=str[i]-'a';
20         if(!rec[root][t])
21             rec[root][t]=++tot;
22         flag[rec[root][t]]++;
23         root=rec[root][t];
24 
25     }
26 }
27 int judge(char *str)
28 {
29     int root=0;
30     int len=strlen(str);
31     for(int i=0; i<len; i++)
32     {
33         int t=str[i]-'a';
34         if(rec[root][t]==0)
35             return 0;
36         root=rec[root][t];
37         //cout<<i<<endl;
38     }
39     return flag[root];
40 }
41 void init()
42 {
43     for(int i=0; i<tot; i++)
44     {
45         for(int j=0; j<30; j++)
46         {
47             rec[i][j]=0;
48         }
49     }
50     tot=0;
51 }
52 int main()
53 {
54     tot=0;
55     while(gets(str1))
56     {
57         if(str1[0]=='\0') break;
58         add(str1);
59     }
60     while(scanf("%s",str1)!=EOF)
61     {
62         printf("%d\n",judge(str1));
63     }
64     return 0;
65 }
66    // init();
67 //    while(gets(str1))
68 //    {
69 //        if(str1[0]=='\0')
70 //            break;
71 //        scanf("%s",str1);
72 //        add(str1);
73 //        getchar();
74 //    }
75 //    while(scanf("%s",str1)!=EOF)
76 //    {
77 //        int ans=judge(str1);
78 //        //cout<<str1<<endl;
79 //        printf("%d\n",ans);
80 //    }
81 //    return 0;
82 //}

 

B题:

分割字符串

版本一:使用函数 stringstream (头文件<sstream>)

https://blog.csdn.net/weixin_35929051/article/details/52502486?tdsourcetag=s_pcqq_aiomsg(stringstream的使用说明)

#include<iostream>
#include<stack>
#include<string>
#include<cstring>
#include<sstream>
#include<stdio.h>
using namespace std;
# define ll long long
const int maxn = 1e6+100;
int rec[maxn][30];
int flag[maxn];
int tot,ans;
string tmp,str1;
void add(string str)
{
    int root=0;
    int len=str.size();
    for(int i=0; i<len; i++)
    {
        int t=str[i]-'a';
        if(!rec[root][t])
            rec[root][t]=++tot;
        root=rec[root][t];
    }
    if(flag[root]==0)
        ans++;
    flag[root]=1;
}
void init()
{
   // memset(flag,0,sizeof(flag));
    for(int i=0; i<=tot; i++)
    {
        flag[i]=0;
        for(int j=0; j<30; j++)
        {
            rec[i][j]=0;
        }
    }
    tot=0,ans=0;
}
int main()
{
    while(getline(cin,str1))
    {
        //cout<<str1<<endl;
        init();
        int p=0,t=0;
        if(str1=="#")
            break;
        stringstream ss(str1);
        while(ss>>str1)
        {
            add(str1);
        }
        cout<<ans<<endl;
       // cout<<tot<<endl;
    }
    return 0;
}

 

版本二:(超时)

#include<iostream>
#include<stack>
#include<string>
#include<cstring>
#include<stdio.h>
using namespace std;
# define ll long long
const int maxn = 1e6+100;
int rec[maxn][30];
int flag[maxn];
int tot,ans;
char tmp[maxn],str1[maxn];
void add(char *str)
{
    int root=0;
    int len=strlen(str);
    for(int i=0; i<len; i++)
    {
        int t=str[i]-'a';
        if(!rec[root][t])
            rec[root][t]=++tot;
        root=rec[root][t];
    }
    if(flag[root]==0)ans++;
    flag[root]=1;
}
void init()
{
    for(int i=0; i<=tot; i++)
    {
        flag[i]=0;
        for(int j=0; j<30; j++)
        {
            rec[i][j]=0;
        }
    }
    tot=0,ans=0;
}
int main()
{
    tot=0;
    while(gets(str1))
    {
        init();
        int p=0,t=0;
        if(str1[0]=='#')
            break;
        int len=strlen(str1);
        while(p<len)
        {
            while(str1[p]!=' '&&p<len)
            {
                tmp[t++]=str1[p];
                p++;
            }
            while(str1[p]==' '&&p<len)
            p++;
            add(tmp);
            t=0;
        }
        printf("%d\n",ans);
        getchar();
    }
    return 0;
}

 

01字典树:

首先输入n个数,然后每次输入一个数k,寻找输入的这个数和前面的n个数中的某一个最大的异或值?也就是k^s最大?

 1 #include <iostream>
 2 #include <string>
 3 #include <deque>
 4 #include <stack>
 5 #include<cmath>
 6 #include <algorithm>
 7 #include<map>
 8 using namespace std;
 9 # define ll long long
10 # define inf 0x3f3f3f3f
11 const int maxn = 3e6+100;
12 ll flag[maxn];
13 int tot;
14 int sto[maxn][4];
15 void init()
16 {
17     for(int i=0; i<=tot; i++)
18     {
19         flag[i]=0;
20         for(int j=0; j<3; j++)
21         {
22             sto[i][j]=0;
23         }
24     }
25 }
26 void add(ll t)
27 {
28     ll u=0;
29     for(ll i=32; i>=0; i--)
30     {
31         ll tmp=(t>>i)&1;
32         if(sto[u][tmp]==0)
33             sto[u][tmp]=++tot;
34         u=sto[u][tmp];
35     }
36     flag[u]=t;
37 }
38 ll query(ll t)
39 {
40     ll u=0;
41     for(ll i=32; i>=0; i--)
42     {
43         ll tmp=(t>>i)&1;
44         if(sto[u][tmp^1])
45             u=sto[u][tmp^1];
46         else
47             u=sto[u][tmp];
48     }
49     return flag[u];
50 }
51 int main()
52 {
53     int T;
54     scanf("%d",&T);
55     tot=0;
56     int Case=0;
57     while(T--)
58     {
59         init();
60         int n,m;
61         scanf("%d %d",&n,&m);
62         int tmp;
63         for(int i=1; i<=n; i++)
64         {
65             scanf("%d",&tmp);
66             add(tmp);
67         }
68         printf("Case #%d:\n",++Case);
69         for(int i=1; i<=m; i++)
70         {
71             scanf("%d",&tmp);
72             int ans=query(tmp);
73             printf("%d\n",ans);
74         }
75     }
76     return 0;
77 }

 

01字典树 

HDU - 5536 

具体思路:题目中说的是找三个不同的i,j,k,使得(a[i]+a[j])^a[k]的值最大,那么思路来了,首先第一步,我们先把所有的值全部存到字典树里面,然后两个for循环,每一次先把a[i]和a[j]去掉,然后再去求(a[i]+a[j])在字典树中的最值就可以了。

AC代码:

  1 #include <iostream>
  2 #include <string>
  3 #include <deque>
  4 #include <stack>
  5 #include<cmath>
  6 #include <algorithm>
  7 #include<map>
  8 using namespace std;
  9 # define ll long long
 10 # define inf 0x3f3f3f3f
 11 # define ll_inf 1ll<<60
 12 const int maxn = 1e6+100;
 13 ll sto[maxn][3];
 14 ll flag[maxn];
 15 ll a[maxn],tot;
 16 ll com[maxn];
 17 ll Max(ll t1,ll t2)
 18 {
 19     if(t1<t2)
 20         return t2;
 21     return t1;
 22 }
 23 void init()
 24 {
 25     for(int i=0; i<=tot; i++)
 26     {
 27         flag[i]=0;
 28         com[i]=0;
 29         for(int j=0; j<3; j++)
 30         {
 31             sto[i][j]=0;
 32         }
 33     }
 34     tot=0;
 35 }
 36 void add(ll t)
 37 {
 38     int u=0;
 39     for(int i=32; i>=0; i--)
 40     {
 41         int tmp=(t>>i)&1;
 42         if(sto[u][tmp]==0)
 43             sto[u][tmp]=++tot;
 44         flag[sto[u][tmp]]++;
 45         u=sto[u][tmp];
 46     }
 47     com[u]=t;//存储这一位上是哪个数
 48 }
 49 void Erase(ll t)
 50 {
 51     int u=0;
 52     for(int i=32; i>=0; i--)
 53     {
 54         int tmp=(t>>i)&1;
 55         flag[sto[u][tmp]]--;//把这个数的路径走过的减去1,就相当于把这个数从树上去掉。
 56         u=sto[u][tmp];
 57     }
 58    // com[u]=0;
 59 }
 60 ll query(ll t)
 61 {
 62     int u=0;
 63     for(int i=32; i>=0; i--)
 64     {
 65         int tmp=(t>>i)&1;
 66         if(sto[u][tmp^1]>0)//看一下当前这一位上是不是有不一样的
 67         {
 68             if(flag[sto[u][tmp^1]]>0)//如果有,就按照不同进行
 69                 u=sto[u][tmp^1];
 70             else// 没有的话,就按照另外一种来进行
 71                 u=sto[u][tmp];
 72         }
 73         else
 74         {
 75             if(flag[sto[u][tmp]]>0)//同理
 76                 u=sto[u][tmp];
 77             else
 78                 u=sto[u][tmp^1];
 79         }
 80     }
 81     return com[u]^t;
 82 }
 83 int main()
 84 {
 85     int T;
 86     tot=0;
 87     scanf("%d",&T);
 88     while(T--)
 89     {
 90         init();
 91         int n;
 92         scanf("%d",&n);
 93         for(int i=1; i<=n; i++)
 94         {
 95             scanf("%lld",&a[i]);
 96             add(a[i]);
 97         }
 98         ll maxx=0;
 99         for(int i=1; i<=n; i++)
100         {
101             Erase(a[i]);
102             for(int j=i+1; j<=n; j++)
103             {
104                 Erase(a[j]);
105                 maxx=Max(maxx,query(a[i]+a[j]));
106                 add(a[j]);
107             }
108             add(a[i]);
109         }
110         printf("%lld\n",maxx);
111     }
112     return 0;
113 }

 

posted @ 2018-12-22 20:08  Let_Life_Stop  阅读(460)  评论(0编辑  收藏  举报