Trie(前缀树,字典树)

It’s advantage is, LCP (Longest Common Prefix) of two of these strings is the LCA (Lowest Common Ancestor) of their nodes in the trie(a node that we can build the string by writing down the characters in the path from the root to that node).

Generating the trie :
Root is vertex number 0 (C++)

int x[MAX_NUMBER_OF_NODES][MAX_ASCII_CODE], next = 1; //initially all numbers in x are -1
void build(string s){
    int i = 0, v = 0;
    while(i < s.size()){
        if(x[v][s[i]] == -1)
            v = x[v][s[i++]] = next ++;
        else
            v = x[v][s[i++]];
    }
}

————————
Trie模板
LA 3942 https://vjudge.net/problem/UVALive-3942

// Trie版
// LA  3942
#include<bits/stdc++.h>
#define pb push_back 
#define mp make_pair
using namespace std;

const int maxn=4e5+7;
typedef long long ll;

struct Trie{
    const static int Maxn=4e5+7;
    int ch[Maxn][26],val[Maxn],sz;

    void init()
    {
        sz=1;
        memset(ch,0,sizeof(ch));
        memset(val,0,sizeof(val));
    }

    void insert(char *s)
    {
        int len=strlen(s);
        int u=0;
        for(int i=0;i<len;++i)
        {
            int c=s[i]-'a';
            if(!ch[u][c])
            {
                ch[u][c]=sz++;
            }
            u=ch[u][c];
        }
        val[u]++;
    }

    vector<int> search(char *s)
    {
        vector<int>res;
        int len=strlen(s);
        int u=0;
        for(int i=0;i<len;++i)
        {
            int c=s[i]-'a';
            if(!ch[u][c]) break;
            u=ch[u][c];
            if(val[u]>0)
              res.pb(i+1);
        }
        return res;
    }
}trie;

int n;
char t[300005],s[300005];
int dp[300005];
int mod=20071027;


int main()
{
    int i,j,k,T=0;
    while(scanf("%s%d",t,&n)!=EOF)
    {
        T++;
        int ans=0;
        trie.init();
        int len=strlen(t);
        memset(dp,0,sizeof(dp));

        for(i=1;i<=n;++i)
        {
            scanf("%s",s);
            trie.insert(s);
        }

        dp[len]=1;
        for(i=len-1;i>=0;--i)
        {
            vector<int>tmp=trie.search(t+i);
            int len2=tmp.size();
            for(j=0;j<len2;++j)
            {
                int len3=tmp[j];
                dp[i]+=dp[i+len3];
            }
            dp[i]%=mod;
        }

        ans=dp[0];

        printf("Case %d: %d\n",T,ans);

    }


    return 0;
}

此题也是一道经典的处理子串的问题,子串=母串从某节点开始的前缀,所以想到用trie
不知为何常数特别大(和传vector参数无关),2400ms+,leaderboard上是60ms
————————

01Trie 练习题 一般和异或、位运算有关
http://acm.uestc.edu.cn/#/problem/show/1582

#include<bits/stdc++.h>
#define pb push_back 
#define mp make_pair
using namespace std;

const int maxn=1;
typedef long long ll;

struct Trie{
    const static int Maxn=4e6+7;
    int ch[Maxn][2],sz,val[Maxn];
    void init()
    {
        sz=1;
        memset(ch,0,sizeof(ch));
        memset(val,0,sizeof(val));
    }

    void insert(int now)
    {
        int u=0;
        for(int i=30;i>=0;--i)
        {
            int c=(now>>i)&1;
            if(!ch[u][c])
            {
                ch[u][c]=sz++;
            }
            u=ch[u][c];
        }
        val[u]=now;
    }

    int search(int now)
    {
        int u=0;
        for(int i=30;i>=0;--i)
        {
            int c=(now>>i)&1;
            if(ch[u][c^1])
            {
                u=ch[u][c^1];
            }
            else
            {
                u=ch[u][c];
            }
        }
        return now^val[u];
    }

}trie;

int n,m;
/* 
string trans(int now)
{
    string a="";
    for(int i=0;i<31;++i)
    {
        char c=now%2+'0';
        a=c+a;
        now/=2;
    }
    return a;
}*/ 

int main()
{
    int i,j,k,T;
    trie.init();
    scanf("%d",&n);
    for(i=1;i<=n;++i)
    {
        scanf("%d",&j);
        trie.insert(j);
    }

    scanf("%d",&m);
    for(i=1;i<=m;++i)
    {
        scanf("%d",&j);
        printf("%d\n",trie.search(j));
    }

    return 0;
}

注意不要转为字符串,运用位运算会提高效率,实测效率提高5倍

这里写图片描述
————————
另一道01trie:
http://acm.uestc.edu.cn/#/problem/show/1670
注意连续异或的性质:
[l,r]连续异或=pre[r]^pre[l-1]

————————
————————

边值不确定,范围较大时,用map
http://acm.uestc.edu.cn/#/problem/show/1564

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

const int maxn=1e5+7;
typedef long long ll;

int n;
int sh[10000001],prim[7000001],a[maxn];
vector<int>p[maxn];

map<int,int>ch[maxn*26];
int val[maxn*26];
int sz=1;

ll sum;

void insert(int x)
{
    int i,j,len=p[x].size(),u=0;
    for(i=0;i<len;++i)
    {
        int v=p[x][i];
        if(!ch[u][v])
        {
            val[sz]=0;
            ch[u][v]=sz++;
        }
        u=ch[u][v];
        val[u]++;
    }
}

void search(int x)
{
    int i,j,len=p[x].size(),u=0,now=1;
    int pre=val[1];

    for(i=0;i<len;++i)
    {
        int v=p[x][i];
        u=ch[u][v];
        sum+=(ll(pre)-ll(val[u]))*now;
        pre=val[u];
        now*=v;
    }

    if(now==a[x]) pre--;
    sum+=(ll)now*ll(pre);
}

int main()
{
    int i,j,k;
    scanf("%d",&n);
    for(i=1;i<=n;++i)
      scanf("%d",&a[i]);

    prim[0]=1;
    prim[1]=2;
    int num=2;
    int sq=sqrt(1e4);
    for(i=3;i<=1e4;i+=2)
    {
        if(sh[i]==1) continue;
        prim[num]=i;
        num++;
        sh[i]=1;
        if(i>sq) continue;  
        for(j=i*i;j<=1e4;j+=2*i)
        {
            sh[j]=1;
        }
    }

    //printf("%d",num);

    for(i=1;i<=n;++i)
    {
        p[i].push_back(1);
        int v=a[i];
        int q=sqrt(a[i]);
        int nu=1;
        while(nu<num&&v>1)
        {
            if(prim[nu]>q)
            {
                p[i].push_back(v);
                break;
            }
            while(v%prim[nu]==0)
            {
                v/=prim[nu];
                p[i].push_back(prim[nu]);
            }
            nu++;
        }
    }

    /*
    for(i=1;i<=n;++i)
    {
        a[i]=1;int len=p[i].size();
        for(j=0;j<len;++j)
        {
            a[i]*=p[i][j];
        }
    }*/

    /*
    for(i=1;i<=n;++i)
    {
        int len=p[i].size();
        for(j=0;j<len;++j)
          printf("%d ",p[i][j]);
        printf("\n");
    }*/


    //memset(ch[0],0,sizeof(ch[0]));
    for(i=1;i<=n;++i)
      insert(i);

    /*
    for(i=0;i<sz;++i)
      printf("%d %d\n",i,val[i]);
    */

    for(i=1;i<=n;++i)
      search(i);

    printf("%lld\n",sum/2);

}

虽然此题还可以不用trie,而是用一个f数组的每个值表示每个节点(其实和字符串map前缀代替trie差不多,只不过对字符串这样多半会T,而对此题反而优化),代替trie。

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

const int maxn=1e5+7;
typedef long long ll;

int n;
int sh[10000001],prim[7000001],a[maxn];
vector<int>p[maxn];

int f[10000001];
ll sum;

int main()
{
    int i,j,k;
    scanf("%d",&n);
    for(i=1;i<=n;++i)
      scanf("%d",&a[i]);

    prim[0]=1;
    prim[1]=2;
    int num=2;
    int sq=sqrt(3200);
    for(i=3;i<=3200;i+=2)
    {
        if(sh[i]==1) continue;
        prim[num]=i;
        num++;
        sh[i]=1;
        if(i>sq) continue;  
        for(j=i*i;j<=3200;j+=2*i)
        {
            sh[j]=1;
        }
    }

    //printf("%d",num);

    for(i=1;i<=n;++i)
    {
        p[i].push_back(1);
        int v=a[i];
        int q=sqrt(a[i]);
        int nu=1;
        while(nu<num&&v>1)
        {
            if(prim[nu]>q)
            {
                p[i].push_back(v);
                break;
            }
            while(v%prim[nu]==0)
            {
                v/=prim[nu];
                p[i].push_back(prim[nu]);
            }
            nu++;
        }
    }


    for(i=1;i<=n;++i)
    {
        int now=1,pre;
        int len=p[i].size();
        for(j=0;j<len;++j)
        {
            int v=p[i][j];
            pre=f[now]-1;
            if(j>=1)
              sum+=(ll)(pre-f[now*v])*(ll)now;
            now*=v;
            if(j==len-1) sum+=ll(now)*f[now];
            f[now]++;
        }
    }

    printf("%lld",sum);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值