题目大意:给定模板串
s
s
s,和一个长度为
m
m
m的询问序列,每个询问操作为把询问串的
l
l
l到
r
r
r的子串在模板串中的出现次数,共
Q
Q
Q个真正的询问,每个会给定一个长度为
k
k
k的串,问操作
[
L
,
R
]
[L,R]
[L,R]的询问答案之和。
∣
s
∣
,
m
,
q
×
k
≤
1
0
5
|s|,m,q\times k\leq 10^5
∣s∣,m,q×k≤105
做法:对题目稍加观察,
q
×
k
q\times k
q×k和
1
0
5
10^5
105的数据范围有明显提示,可以确定根据
k
k
k与
m
\sqrt m
m的关系进行数据分治,对于
k
≤
m
k\leq \sqrt m
k≤m的,具有的特点是每个询问的串长小,这样就可以对每一个后缀直接插入
S
A
M
SAM
SAM进行询问。而
k
>
m
k>\sqrt m
k>m时,特点为
q
q
q较小,可以直接把对应询问序列里面的询问拆解,逐个询问。而对于出现多少次,可以把模板串和询问串放在一起建
S
A
SA
SA,每次找到区间最小值分治。这样我们按照询问长度从大到小的顺序询问,在询问长度减小的过程中会不断有分治的区间合并。采用分块的方式来区间加单点求和。
时间复杂度:
O
(
q
k
m
)
O(qk\sqrt m)
O(qkm)
感觉有很多更简洁的做法,我写了5k。还是太菜了,下次希望想一点简便的做法。
代码:
#include<iostream>
#include<cstring>
#include<cassert>
#include<cmath>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<vector>
#include<time.h>
#include<bitset>
#include<cstdio>
#include<algorithm>
using namespace std;
#define REP(i,x,y) for(int i=x;i<=y;i++)
#define rep(i,n) REP(i,1,n)
#define rep0(i,n) REP(i,0,n-1)
#define repG(i,x) for(int i=pos[x];~i;i=e[i].next)
#define ll long long
#define db double
const int N=3e5+7;
const int INF=1e9+7;
namespace seg{
const int T=320;
int tg[N],a[N];
void ins(int L,int R,int v){
if(L/T==R/T){
REP(i,L,R)a[i]+=v;
return;
}
while(L%T!=0)a[L++]+=v;
a[R]+=v;
while(R%T!=0)a[--R]+=v;
REP(i,L/T,R/T-1)tg[i]+=v;
}
int check(int x){return a[x]+tg[x/T];}
}
namespace SA{
int n,cnt;
int a[N],sa[N],ra[N],ns[N],nr[N],ls[N],ct[N],nw[N],mn[N*2],sm[N];
char s[N];
struct pir{int x,v;}p[N],h[N][22];
pir mer(pir a,pir b){return (a.v<b.v)?a:b;}
bool cmp(pir a,pir b){return a.v<b.v;}
struct tri{int x,l,r,v;}t[N*2];
bool cmp2(tri a,tri b){return a.x>b.x;}
pir check(int L,int R){
int k=mn[R-L+1];
return mer(h[L][k],h[R-(1<<k)+1][k]);
}
void solve(int l,int r){
if(l==r)return;
pir o=check(l,r-1);
t[++cnt]=(tri){o.v,l,o.x,sm[r]-sm[o.x]};
t[++cnt]=(tri){o.v,o.x+1,r,sm[o.x]-sm[l-1]};
if(!r)return;
solve(l,o.x);
solve(o.x+1,r);
}
void wk(){
rep(i,n)p[i]=(pir){i,a[i]};
sort(p+1,p+n+1,cmp);
int las=1;
rep(i,n){
if(p[i].v!=p[i-1].v)las=i;
ra[p[i].x]=las;
sa[i]=p[i].x;
}
for(int i=1;i<n;i<<=1){
rep(j,n)ct[j]=ls[j]=nw[j]=-1;
REP(j,n-i+1,n){
nw[ra[j]]++;
ns[ra[j]]=j;
nr[j]=ra[j];
}
rep(j,n){
if(sa[j]<=i)continue;
int p=sa[j]-i;
nw[ra[p]]++;
if(ra[sa[j]]!=ct[ra[p]]){
ct[ra[p]]=ra[sa[j]];
ls[ra[p]]=nw[ra[p]];
}
ns[ra[p]+nw[ra[p]]]=p;
nr[p]=ra[p]+ls[ra[p]];
}
rep(j,n)sa[j]=ns[j],ra[j]=nr[j];
}
int ans=0;
rep(i,n){
if(ra[i]==n){
ans=0;
continue;
}
if(ans)ans--;
int p=sa[ra[i]+1];
while(a[p+ans]==a[i+ans]&&i+ans<=n&&p+ans<=n)ans++;
h[ra[i]][0]=(pir){ra[i],ans};
}
for(int i=1;(1<<i)<n;i++){
rep(j,n-(1<<i))h[j][i]=mer(h[j][i-1],h[j+(1<<(i-1))][i-1]);
REP(j,(1<<i)+1,(1<<(i+1)))mn[j]=i;
}
}
void init(int *b,int nn,int gg){
n=nn;
cnt=0;
rep(i,n)a[i]=b[i];
wk();
rep(i,gg)sm[ra[i]]++;
rep(i,n)sm[i]+=sm[i-1];
solve(1,n);
sort(t+1,t+cnt+1,cmp2);
}
}
int n,m,Q,K;
namespace D1{
int L[N],R[N],wa[N],bg[N],u[N],v[N],p[N];
ll Ans[N];
int cnt,tot;
char s[N];
vector<int>g[N];
bool cmp(int x,int y){return (R[x]-L[x])>(R[y]-L[y]);}
void solve(){
scanf("%s",s+1);
cnt=tot=0;
rep(i,n)wa[++cnt]=s[i]-'a';
rep(i,m)scanf("%d%d",&L[i],&R[i]);
rep(i,m)L[i]++,R[i]++;
rep(i,Q){
scanf("%s%d%d",s+1,&u[i],&v[i]);
u[i]++;
v[i]++;
wa[++cnt]=-1;
bg[i]=cnt;
rep(j,K)wa[++cnt]=s[j]-'a';
REP(j,u[i],v[i])g[j].push_back(i);
}
SA::init(wa,cnt,n);
rep(i,m)p[i]=i;
sort(p+1,p+m+1,cmp);
int nw=1;
rep(i,m){
while(nw<=SA::cnt&&SA::t[nw].x>=R[p[i]]-L[p[i]]+1){
seg::ins(SA::t[nw].l,SA::t[nw].r,SA::t[nw].v);
nw++;
}
for(int j=0;j<g[p[i]].size();j++){
int d=g[p[i]][j];
Ans[d]+=(ll)seg::check(SA::ra[bg[d]+L[p[i]]]);
}
}
rep(i,Q)printf("%lld\n",Ans[i]);
}
}
namespace D2{
const int T=320;
int L[N],R[N],sz[N],sm[T][T];
char s[N],sv[N];
vector<int>sg[N];
struct sam{
int p,l;
int to[26];
}t[N*2];
int cnt,ls,tot;
int ins(int x){
t[++cnt].l=t[ls].l+1;
int i=ls;
ls=cnt;
for(;i;i=t[i].p){
if(t[i].to[x])break;
t[i].to[x]=cnt;
}
if(!i){t[cnt].p=1; return ls;}
int q=t[i].to[x];
if(t[q].l==t[i].l+1){t[cnt].p=q; return ls;}
t[++cnt]=t[q];
t[cnt].l=t[i].l+1;
t[ls].p=cnt;
t[q].p=cnt;
for(;i;i=t[i].p){
if(t[i].to[x]!=q)break;
t[i].to[x]=cnt;
}
return ls;
}
vector<int>E[N];
void dfs(int x){
for(int j=0;j<E[x].size();j++){
dfs(E[x][j]);
sz[x]+=sz[E[x][j]];
}
}
struct pir{int x,v,d;}tt[N];
bool cmp(pir u,pir v){return u.x<v.x;}
void solve(){
scanf("%s",s+1);
cnt=ls=1;
tot=0;
rep(i,n)sz[ins(s[i]-'a')]++;
REP(i,2,cnt)E[t[i].p].push_back(i);
dfs(1);
rep(i,m)scanf("%d%d",&L[i],&R[i]);
rep(i,m)L[i]++,R[i]++;
rep(i,Q){
scanf("%s",s+1);
rep(j,K){
sv[(i-1)*K+j]=s[j];
rep(k,K+1)sg[(i-1)*K+j].push_back(0);
}
int x,y; scanf("%d%d",&x,&y);
x++; y++;
if(x>1)tt[++tot]=(pir){x-1,-1,i};
tt[++tot]=(pir){y,1,i};
}
sort(tt+1,tt+tot+1,cmp);
int nw=1;
rep(i,m){
sm[L[i]][R[i]]++;
while(nw<=tot&&tt[nw].x==i){
rep(j,K)REP(k,j,K)sg[(tt[nw].d-1)*K+j][k]+=tt[nw].v*sm[j][k];
nw++;
}
}
rep(i,Q){
ll ans=0;
int bb=(i-1)*K;
rep(j,K){
int nw=1;
REP(k,j,K){
if(!t[nw].to[sv[bb+k]-'a'])break;
nw=t[nw].to[sv[bb+k]-'a'];
ans+=(ll)sg[bb+j][k]*sz[nw];
}
}
printf("%lld\n",ans);
}
}
}
int main(){
scanf("%d%d%d%d",&n,&m,&Q,&K);
if(K*K>=m)D1::solve();
else D2::solve();
return 0;
}
由于疫情的原因,闲着也是闲着,就写了这篇博客