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
#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;iint 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;iint 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;jint 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
#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
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;iint 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;iint 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(nu1)
        {
            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

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


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

    /*
    for(i=0;i

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

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

}

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

#include
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(nu1)
        {
            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;jint 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;
}

你可能感兴趣的:(字符串)