神牛的养成计划---可持久化trie

题目大意

给定n个由小写字母组成的字符串。现在有m个询问,每个询问指定两个字符串s1,s2.要求回答:在给定的n个字符串中,有多少个字符串s满足:s1是s的前缀且s2是s的后缀。强制在线!

数据范围

nL12106ms1,s2L22106,n2000m100000.

限制

时间限制:1s
空间限制:256M (512M) (原题限制256M,这个太丧心病狂了!作为蒟蒻,我只会写512M限制的!)

题解

对给定的n个字符串建一棵字典树.对于询问,我们先在trie上匹配,假设最后停在了p节点,那么所有满足条件的字符串s的末尾节点一定是在p的子树中的。如果我们把原字符串按照字典序排序(其实就是trie的dfs序),那么满足条件的s所对应的编号一定落在某个连续区间内。于是我们用可持久化trie维护后缀就好了。

第一次写可持久化trie,感觉还算比较好写。

看别人的题解,都是自定义cmp函数,然后sort一下。只有我蠢蠢地按dfs序排序。

代码

#include 
#include 
#include 
#include 
#include 
using namespace std; 
#define MAXN 2000100 
char s[MAXN],t[MAXN]; 
int _l[MAXN],_r[MAXN]; 
int n,m,tot=1; 
int to[MAXN][26],rt[MAXN],nxt[MAXN][26],summ[MAXN],mn[MAXN],mx[MAXN],order[MAXN]; 
int C[MAXN]; 
vector<int>P[MAXN]; 
void ins(int id) 
{ 
    int x,p=1; 
    for(int i=0;t[i]!='\0';i++) 
    { 
        x=t[i]-'a'; 
        if(!to[p][x]) 
        { 
            to[p][x]=++tot; 
        } 
        p=to[p][x]; 
    } 
    P[p].push_back(id); 
    return ; 
} 
int tim=0; 
const int inf=0x3c3c3c3c; 
void dfs(int p) 
{ 
    mn[p]=inf; 
    mx[p]=0; 
    for(int i=0;ifor(int i=0;i<26;i++) 
    { 
        if(to[p][i]) 
        { 
            dfs(to[p][i]); 
            mn[p]=min(mn[p],mn[to[p][i]]); 
            mx[p]=max(mx[p],mx[to[p][i]]); 
        } 
    } 
    return ; 
} 
bool cmp(int a,int b) 
{ 
    return order[a]void ins2(int& p,int f,int d,int pp) 
{ 
    p=++tot; 
    summ[p]=summ[f]+1; 
    memcpy(nxt[p],nxt[f],sizeof(nxt[f])); 
    if(d>pp) 
    { 
        ins2(nxt[p][s[d]-'a'],nxt[f][s[d]-'a'],d-1,pp); 
    } 
    return ; 
} 
int lstans=0; 
int main() 
{ 
    scanf("%d",&n); 
    for(int i=1,tmp;i<=n;i++) 
    { 
        scanf("%s",t); 
        _l[i]=_r[i-1]+1; 
        tmp=strlen(t); 
        _r[i]=_l[i]+tmp-1; 
        for(int j=0;j1); 
    sort(C+1,C+1+n,cmp); 
    tot=1; 
    for(int i=1,I;i<=n;i++) 
    { 
        I=C[i]; 
        ins2(rt[i],rt[i-1],_r[I],_l[I]); 
    } 
    int L,R; 
    scanf("%d",&m); 
    for(int i=1;i<=m;i++) 
    { 
        scanf("%s",t); 
        L=inf; 
        R=0; 
        int x=1; 
        for(int c,j=0;t[j]!='\0';j++) 
        { 
            c=t[j]-'a'; 
            c=c+lstans; 
            c%=26;//这个傻逼错误,我调了半天才发现!!c-=c>=26?26:0; 
            x=to[x][c]; 
        } 
        if(x) 
        { 
            L=mn[x]; 
            R=mx[x]; 
        } 
        scanf("%s",t); 
        if(L>R) 
        { 
            lstans=0; 
        } 
        else 
        { 
            int x=rt[L-1],y=rt[R],c,nn=strlen(t); 
            for(int j=nn-1;j>=0;j--) 
            { 
                c=t[j]-'a'; 
                c=c+lstans; 
                c%=26;//c-=c>=26?26:0; 
                x=nxt[x][c]; 
                y=nxt[y][c]; 
            } 
            lstans=summ[y]-summ[x]; 
        } 
        printf("%d\n",lstans); 
    } 
    return 0; 
}

你可能感兴趣的:(题解)