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

来源:互联网 发布:冠能狗粮网络代理 编辑:程序博客网 时间:2024/05/29 14:40

题目大意

给定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<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<vector> 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;i<P[p].size();i++)     {         order[P[p][i]]=++tim;         mn[p]=min(mn[p],tim);         mx[p]=max(mx[p],tim);     }     for(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]<order[b]; } 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;j<tmp;j++)         {             s[_l[i]+j]=t[j];         }         C[i]=i;         ins(i);     }     dfs(1);     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; }
原创粉丝点击