【UNR #6】Border 的第五种求法
【UNR #6】Border 的第五种求法
by AmanoKumiko
Description
给出一个长为\(n\)的字符串\(s\),以及一个长为\(n\)的序列\(f\)
有\(m\)次询问,每次给出一个区间\(l,r\)
对于\(s[l\cdots r]\)的所有\(border\),令其出现次数为\(c\),求\(\sum f_c\)
Input
第一行两个数\(n,m\)
Output
\(m\)行每行一个数表示答案
Sample Input
5 4
ababa
1 2 3 4 5
2 3
2 4
1 4
1 5
Sample Output
2
3
3
6
Data Constraint
\(1\le n,m\le 5*10^5\)
Solution
首先这是道板题
我们考虑最暴力的做法
就是计算\(s[l\cdots r]\)和其每个前缀的\(LCS\),看它是不是\(border\)
可以直接做\(DAG\)链剖分
那么找到\(s[l\cdots r]\)在\(DAG\)链上对应的点
只要这些点在\(parent\)数上对应的点是\(s[1\cdots r]\)的祖先,就可以对答案贡献
简单数一数就可以了
设路径数为\(S\)
时间复杂度\(O(n\log n+q\log S\log n)\)
Code
#include<bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i=a;i<=b;i++)
#define Fd(i,a,b) for(int i=a;i>=b;i--)
#define mo 998244353
#define N 500010
#define LL long long
int mod(int x){return x>=mo?x-mo:x;}
LL ans[N];
int n,m,f[N],pw[N],ipw[N],h[N],ed[N];
char s[N];
struct SAM{
vector<int>e[N*2];
LL s1[N*2],s2[N*2];
int ch[N*2][26],link[N*2],len[N*2],sum[N*2],u,rt,tot,lst;
int nxt[N*2],pre[N*2],son[N*2],rk[N*2],top[N*2],wh[N*2],num;
int line[N*2],cnt,d[N*2];
int g[N*2],pos[N*2];
int *tg[N*2],*tp[N*2];
int vis[N*2],sz[N*2];
void build(){
tot=rt=lst=1;
F(i,1,n){
int u=++tot,v=lst,p=s[i]-'a';
for(;v&&!ch[v][p];v=link[v])ch[v][p]=u,len[u]=max(len[u],len[v]+1);
if(!v)link[u]=rt;
else if(len[ch[v][p]]==len[v]+1)link[u]=ch[v][p];
else{
int clone=++tot,Old=ch[v][p];
len[clone]=len[v]+1;
F(j,0,25)ch[clone][j]=ch[Old][j];
link[clone]=link[Old];
link[Old]=link[u]=clone;
for(;v&&ch[v][p]==Old;v=link[v])ch[v][p]=clone;
}
ed[i]=u;
sum[lst=u]++;
}
F(i,1,tot)e[link[i]].push_back(i);
}
void DAG(){
queue<int>q;
F(i,1,tot) F(j,0,25)if(ch[i][j])d[ch[i][j]]++;
q.push(1);
while(!q.empty()){
int u=q.front();q.pop();
line[++cnt]=u;
F(i,0,25)if(ch[u][i]){
d[ch[u][i]]--;
if(!d[ch[u][i]])q.push(ch[u][i]);
}
}
Fd(i,cnt,1){
int u=line[i];s1[u]++;
sum[link[u]]+=sum[u];
F(j,0,25)if(ch[u][j]){
if(s1[ch[u][j]]>s1[nxt[u]])nxt[u]=ch[u][j];
s1[u]+=s1[ch[u][j]];
}
}
F(i,1,cnt){
int u=line[i];s2[u]++;
F(j,0,25)if(ch[u][j]){
if(s2[u]>s2[pre[ch[u][j]]])pre[ch[u][j]]=u;
s2[ch[u][j]]+=s2[u];
}
}
F(i,1,tot) F(j,0,25)if(ch[i][j]){
if(nxt[i]==ch[i][j]&&pre[ch[i][j]]==i)son[i]=ch[i][j],wh[i]=j+1;
}
int tmp=0;
F(i,1,tot){
int u=line[i];
if(vis[u])continue;
int v=u;
sz[u]=1;rk[u]=++num;top[u]=u;
while(son[v])sz[u]++,v=son[v],rk[v]=++num,top[v]=u;
tg[u]=g+tmp;
tp[u]=pos+tmp;
v=u;
int val=0;
F(j,1,sz[u]){
vis[v]=1;
tg[u][j-1]=val;
tp[u][j-1]=v;
val=mod(val+1ll*pw[j-1]*wh[v]%mo);
v=son[v];
}
tmp+=sz[u];
}
}
}S;
struct BIT{
LL sum[N*2];
int lowbit(int x){return -x&x;}
void modify(int x,int y){for(;x<=S.tot;x+=lowbit(x))sum[x]+=y;}
LL qur(int x){LL res=0;for(;x;x-=lowbit(x))res+=sum[x];return res;}
}P;
struct node{int l,r,pos;};
vector<node>ask[N*2];
void calc(int u){
if(u!=1)P.modify(S.rk[u],f[S.sum[u]]);
for(auto v:S.e[u])calc(v);
for(auto d:ask[u]){
ans[d.pos]+=P.qur(d.r)-P.qur(d.l-1);
}
if(u!=1)P.modify(S.rk[u],-f[S.sum[u]]);
}
int main(){
scanf("%d%d",&n,&m);
scanf("%s",s+1);
pw[0]=ipw[0]=1;
F(i,1,n){
pw[i]=37ll*pw[i-1]%mo;
ipw[i]=242816194ll*ipw[i-1]%mo;
h[i]=mod(h[i-1]+1ll*pw[i-1]*(s[i]-'a'+1)%mo);
}
F(i,1,n)scanf("%d",&f[i]);
S.build();
S.DAG();
F(i,1,m){
int l,r;
scanf("%d%d",&l,&r);
int u=1,len=0;
while(len!=r-l+1){
int up=S.top[u],lu=S.rk[u]-S.rk[up];
int le=-1,ri=min(r-l+1-len+1,S.sz[up]-lu),mid;
while(le<ri-1){
mid=le+ri>>1;
if(1ll*mod(S.tg[up][lu+mid]-S.tg[up][lu]+mo)*ipw[lu]%mo==
1ll*mod(h[l+len+mid-1]-h[l+len-1]+mo)*ipw[l+len-1]%mo)le=mid;
else ri=mid;
}
if(le)ask[ed[r]].push_back((node){S.rk[u]+1,S.rk[u]+le,i});
len+=le;u=S.tp[up][lu+le];
if(len!=r-l+1){
u=S.ch[u][s[l+len]-'a'];
ask[ed[r]].push_back((node){S.rk[u],S.rk[u],i});
len++;
}
}
}
calc(1);
F(i,1,m)printf("%lld\n",ans[i]);
return 0;
}