NOI 2018 你的名字 (后缀自动机+线段树合并)
题目大意:略
令$ION2017=S,ION2018=T$
对$S$建$SAM$,每次都把$T$放进去跑,求出结尾是i的前缀串,能匹配上$S$的最长后缀长度为$f_{i}$
由于$T$必须在$[l,r]$上匹配,设现在能匹配的长度为$len$,在后缀自动机的$x$点,添加一个字符$c$,则$trs[x][c]$的$right$集合中必须包含$endpos\in[l+len,r]$,这个操作可以用线段树合并实现
否则$len$就要缩短,直到$len$缩短到$dep[pre_{x}]$,$len$如果再缩短就会无意义,跳$pre$,重复上述操作,直到$len$小于0
求出$f_{i}$以后,我们还要对$T$去重,不去重就会爆零
后缀自动机可以看成一个合并后缀的前缀树,相同的后缀是一定会被合并到一起的,每次都跳到能表示$T_{i-f_{i}+1,i}$的位置
由于每次表示的串不一定能取满这个节点,所以答案是$\sum_{2}^{tot} max(0,dep_{x}-max(dep_{pre_{x}},max(f_{k})))$
仔细一想就能明白这个式子的含义了,考虑不合法的情况,要么$x$表示的串全都能被取,要么只能取到最大的经过它的$f_{i}$,取个补集即可
$upd$:这道题卡$AK$的方式也很细节。
我们把$T$放在$S$上匹配,求以每个位置为后缀,在$S$中的最长匹配长度$Len$时
$Len$应该不断$-1$地缩减,直到缩减到$dep[fa]$,再跳到父节点$fa$,而不是直接缩减到$dep[fa]$
因为我们用线段树合并去检验当前答案$len$是否合法,能取的区间是$[l+len,r]$
如果$len$不合法,说明这个节点能表示的,长度为$len$的串不合法。
如果这个节点还能表示其他长度小于$len$的串,就应该依次检查这些串是否都合法。
代码体现就像我上面说的那样,$len$依次$-1$即可。
时间复杂度依然不变,$len$依次$-1$,而我们从左往右遍历整个$T$串,类似于一个双指针,时间复杂度是$O(n)$级别,算上线段树合并就是$O(nlogn)$
1 #include <cmath> 2 #include <vector> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 #define N1 500010 7 #define S1 (N1<<1) 8 #define ll long long 9 #define uint unsigned int 10 #define rint register int 11 #define dd double 12 #define il inline 13 #define inf 0x3f3f3f3f 14 #define idx(X) (X-'a') 15 using namespace std; 16 17 int gint() 18 { 19 int ret=0,fh=1;char c=getchar(); 20 while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();} 21 while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();} 22 return ret*fh; 23 } 24 int n,len,cnt; 25 /*struct Edge{ 26 int head[S1],to[S1],nxt[S1],cte; 27 void ae(int u,int v){ 28 cte++;to[cte]=v,nxt[cte]=head[u],head[u]=cte;} 29 }E;*/ 30 struct SEG{ 31 int sum[S1*60],ls[S1*60],rs[S1*60],root[S1],tot; 32 int merge(int r1,int r2) 33 { 34 if(!r1||!r2) return r1+r2; 35 int nx=++tot; 36 sum[nx]=sum[r1]+sum[r2]; 37 ls[nx]=merge(ls[r1],ls[r2]); 38 rs[nx]=merge(rs[r1],rs[r2]); 39 return nx; 40 } 41 void update(int x,int l,int r,int &rt) 42 { 43 if(!rt) rt=++tot; 44 sum[rt]++; 45 if(l==r) return; 46 int mid=(l+r)>>1; 47 if(x<=mid) update(x,l,mid,ls[rt]); 48 else update(x,mid+1,r,rs[rt]); 49 } 50 ll query(int L,int R,int l,int r,int rt) 51 { 52 if(!rt||L>R) return 0; 53 if(L<=l&&r<=R) return sum[rt]; 54 int mid=(l+r)>>1;ll ans=0; 55 if(L<=mid) ans+=query(L,R,l,mid,ls[rt]); 56 if(R>mid) ans+=query(L,R,mid+1,r,rs[rt]); 57 return ans; 58 } 59 }s; 60 61 char str[S1]; 62 int L[S1];//sz[S1],psz[S1]; 63 namespace S{ 64 int trs[S1][26],pre[S1],dep[S1],la,tot; 65 void init(){tot=la=1;} 66 void insert(int c,int id) 67 { 68 int p=la,np=++tot,q,nq;la=np; 69 dep[np]=dep[p]+1; 70 for(;p&&!trs[p][c];p=pre[p]) trs[p][c]=np; 71 s.update(id,1,n,s.root[np]); 72 if(!p) {pre[np]=1;return;} 73 q=trs[p][c]; 74 if(dep[q]==dep[p]+1) pre[np]=q; 75 else{ 76 pre[nq=++tot]=pre[q]; 77 pre[q]=pre[np]=nq; 78 dep[nq]=dep[p]+1; 79 memcpy(trs[nq],trs[q],sizeof(trs[q])); 80 for(;p&&trs[p][c]==q;p=pre[p]) trs[p][c]=nq; 81 } 82 } 83 int hs[S1],que[S1]; 84 void topo() 85 { 86 int i,x; 87 for(i=2;i<=tot;i++) hs[dep[i]]++; 88 for(i=1;i<=tot;i++) hs[i]+=hs[i-1]; 89 for(i=2;i<=tot;i++) que[hs[dep[i]]--]=i; 90 for(i=tot-1;i;i--) 91 { 92 x=que[i]; 93 s.root[pre[x]]=s.merge(s.root[x],s.root[pre[x]]); 94 } 95 } 96 inline int Min(int X,int Y){return X<Y?X:Y;} 97 void find(int l,int r) 98 { 99 int i,x=1,c,mi; 100 for(i=1;i<=len;i++) 101 { 102 c=idx(str[i]); 103 L[i]=L[i-1]; 104 while(1) 105 { 106 if(!trs[x][c]||!s.query(l+L[i],r,1,n,s.root[trs[x][c]])) {L[i]--;} 107 else {L[i]++;x=trs[x][c];break;} 108 if(L[i]==-1) {L[i]=0;break;} 109 else if(L[i]==dep[pre[x]]) x=pre[x]; 110 } 111 /*for(;pre[x]&&(!trs[x][c]||!s.query(l+Min(L[i-1],dep[x]),r,1,n,s.root[trs[x][c]]));x=pre[x]); 112 if(!trs[x][c]||){ 113 L[i]=0; 114 }else{ 115 L[i]=min(L[i-1]+1,dep[x]+1); 116 x=trs[x][c]; 117 }*/ 118 } 119 } 120 }; 121 namespace T{ 122 int trs[S1][26],pre[S1],dep[S1],la,tot; 123 void init(){tot=la=1;} 124 void insert(int c) 125 { 126 int p=la,np=++tot,q,nq;la=np; 127 dep[np]=dep[p]+1; 128 for(;p&&!trs[p][c];p=pre[p]) trs[p][c]=np; 129 if(!p) {pre[np]=1;return;} 130 q=trs[p][c]; 131 if(dep[q]==dep[p]+1) pre[np]=q; 132 else{ 133 pre[nq=++tot]=pre[q]; 134 pre[q]=pre[np]=nq; 135 dep[nq]=dep[p]+1; 136 memcpy(trs[nq],trs[q],sizeof(trs[q])); 137 for(;p&&trs[p][c]==q;p=pre[p]) trs[p][c]=nq; 138 } 139 } 140 int ma[S1],hs[S1],que[S1]; 141 ll uniq() 142 { 143 int i,x,c; ll ans=0; 144 for(i=2;i<=tot;i++) hs[dep[i]]++; 145 for(i=1;i<=tot;i++) hs[i]+=hs[i-1]; 146 for(i=2;i<=tot;i++) que[hs[dep[i]]--]=i; 147 x=1; 148 for(i=1;i<=len;i++) 149 { 150 c=idx(str[i]); 151 for(;pre[x]&&dep[pre[x]]>=L[i]-1;x=pre[x]); 152 x=trs[x][c]; 153 ma[x]=max(ma[x],L[i]); 154 } 155 for(i=tot-1;i;i--) 156 { 157 x=que[i]; 158 if(ma[x]) ma[pre[x]]=dep[pre[x]]; 159 } 160 for(x=2;x<=tot;x++) 161 ans+=max(0,dep[x]-max(dep[pre[x]],ma[x])); 162 return ans; 163 } 164 void clr() 165 { 166 tot++; 167 memset(hs,0,tot*4),memset(ma,0,tot*4); 168 memset(que,0,tot*4),memset(pre,0,tot*4); 169 memset(dep,0,tot*4),memset(trs,0,tot*4*26); 170 memset(L,0,(len+1)*4); 171 tot=la=1; 172 } 173 }; 174 175 int main() 176 { 177 freopen("t2.in","r",stdin); 178 //freopen("a.out","w",stdout); 179 int i,j,Q,l,r;ll ans1,ans2; 180 S::init(); 181 scanf("%s",str+1);n=strlen(str+1); 182 for(i=1;i<=n;i++) S::insert(idx(str[i]),i); 183 S::topo(); 184 scanf("%d",&Q); 185 for(i=1;i<=Q;i++) 186 { 187 scanf("%s",str+1); 188 scanf("%d%d",&l,&r); 189 len=strlen(str+1); 190 T::clr(); 191 for(j=1;j<=len;j++) T::insert(idx(str[j])); 192 S::find(l,r); 193 printf("%lld\n",T::uniq()); 194 } 195 return 0; 196 }