[bzoj5417]你的名字

先考虑l=1,r=|s|的部分分,需要求出t每一个前缀的不是s子串的最长后缀,记作pp[k],有以下限制:
1.pp[pos[k]]<len(pos[k]表示k的某一个结束位置),因为不能被匹配
2.len[fa[k]]<len<=len[k],因为这个点上本来就只有这些串
由此得到答案为sigma(max(0,len[j]-max(len[fa[j]],pp[pos[j]])))(要对0取max)
维护出s从li到ri的后缀自动机,但好像不太容易。不妨换个角度,即要求其的right集合存在一个值在[li,ri]之间
也就是说在计算s的SAM同时,求出每一个节点的right集合
维护线段树,线段树下标表示位置,值表示是否是right集合。那么SAM上的父亲就是所有儿子right集合的并,也就是线段树合并
(注意:因为要保留参与合并的线段树,所以要新建节点)
同时线段树还能很方便的判断区间中有没有1,求区间和即可
但是要注意,此时不能直接跳fa,而是要一个一个减长度(因为可能无法匹配该节点最长串,但能匹配较短的串)
  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define N 2000005
  4 #define mid (l+r>>1)
  5 struct ji{
  6     int nex,to;
  7 }edge[N];
  8 int V,x,last,fa[N],pos[N],len[N],ch[N][26];
  9 int VV,E,n,m,a,b,r[N],head[N],pp[N],ls[N*16],rs[N*16];
 10 long long ans;
 11 char s[N],t[N];
 12 int New(){
 13     fa[++V]=0;
 14     len[V]=pos[V]=0;
 15     memset(ch[V],0,sizeof(ch[V]));
 16     return V;
 17 }
 18 void add_edge(int x,int y){
 19     edge[E].nex=head[x];
 20     edge[E].to=y;
 21     head[x]=E++;
 22 }
 23 void add(int c,int id){
 24     int p=last,np=last=New();
 25     len[np]=len[p]+1;
 26     pos[V]=id;
 27     for(;(p)&&(!ch[p][c]);p=fa[p])ch[p][c]=np;
 28     if (!p)fa[np]=x;
 29     else{
 30         int q=ch[p][c];
 31         if (len[q]==len[p]+1)fa[np]=q;
 32         else{
 33             int nq=New();
 34             pos[nq]=pos[q];
 35             len[nq]=len[p]+1;
 36             memcpy(ch[nq],ch[q],sizeof(ch[q]));
 37             fa[nq]=fa[q];
 38             fa[q]=fa[np]=nq;
 39             for(;(p)&&(ch[p][c]==q);p=fa[p])ch[p][c]=nq;
 40         }
 41     }
 42 }
 43 void update(int &k,int l,int r,int x){
 44     k=++VV;
 45     if (l==r)return;
 46     if (x<=mid)update(ls[k],l,mid,x);
 47     else update(rs[k],mid+1,r,x);
 48 }
 49 int query(int k,int l,int r,int x,int y){
 50     if ((!k)||(l>y)||(x>r))return 0;
 51     if ((x<=l)&&(r<=y))return 1;
 52     return query(ls[k],l,mid,x,y)|query(rs[k],mid+1,r,x,y);
 53 }
 54 void merge(int &k1,int k2){
 55     if (k1*k2==0){
 56         k1+=k2;
 57         return;
 58     }
 59     ls[++VV]=ls[k1];
 60     rs[VV]=rs[k1];
 61     k1=VV;
 62     merge(ls[k1],ls[k2]);
 63     merge(rs[k1],rs[k2]);
 64 }
 65 void dfs(int k){
 66     if (pos[k])update(r[k],1,n,pos[k]);
 67     for(int i=head[k];i!=-1;i=edge[i].nex){
 68         dfs(edge[i].to);
 69         merge(r[k],r[edge[i].to]);
 70     }
 71 }
 72 int main(){
 73     scanf("%s%d",s,&m);
 74     len[0]=-1;
 75     n=strlen(s);
 76     x=last=New();
 77     for(int i=0;s[i];i++)add(s[i]-'a',i+1);
 78     memset(head,-1,sizeof(head));
 79     for(int i=2;i<=V;i++)add_edge(fa[i],i);
 80     dfs(1);
 81     x=New();
 82     for(int i=1;i<=m;i++){
 83         scanf("%s%d%d",t,&a,&b);
 84         V=x-1;
 85         last=New();
 86         for(int j=0,k=1,l=0;t[j];pp[j++]=++l){
 87             int c=t[j]-'a';
 88             add(c,j);
 89             while (!query(r[ch[k][c]],1,n,a+l,b)){
 90                 if (--l<0)break;
 91                 if (l==len[fa[k]])k=fa[k];
 92             }
 93             if (l<0)k=1;
 94             else k=ch[k][c];
 95         }
 96         ans=0;
 97         for(int j=x;j<=V;j++)ans+=max(0,len[j]-max(len[fa[j]],pp[pos[j]]));
 98         printf("%lld\n",ans);
 99     }
100 }
View Code

猜你喜欢

转载自www.cnblogs.com/PYWBKTDA/p/11516907.html