CF587F. Duff is Mad
题目描述
题解
知道是分块之后就不难了
把n分块,对于整块建AC自动机暴力跑,散块把全部串建AC自动机之后可以线段树查子树(因为往上查要考虑那些能查那些不能所以不好搞),也可以递归子树时用 出-入 计算
空间卡一卡可以\(n\sqrt n\),如果再把询问[L,R]前缀和一下之后也许可以做到线性
时间O(n√n)
code
#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
#define ll long long
//#define file
using namespace std;
int bg[100001],ed[100001],A[100011],Tm[100001],n,Q,i,j,k,l,len,S,x,y;
bool bz[100001];
ll ans[100001],Ans[100001];
char st[100001],St[100001];
struct type{int x,y,z;} q[100001];
namespace tree{
int a[100011][2],b[50000001],ls[100011],tr[100011][26],fa[100011],d[100011],Ed[100011],i,j,k,l,len=0,h,t,Len;
vector<int> c[100011];
ll f[100011];
void clear() {memset(tr,0,sizeof(tr[0])*(len+1));memset(fa,0,4*(len+1));memset(f,0,8*(len+1));len=0;}
void New(int t,int x) {if (!tr[t][x]) tr[t][x]=++len;}
void NEW(int x,int y) {++Len;a[Len][0]=y;a[Len][1]=ls[x];ls[x]=Len;}
void dfs(int t)
{
int i,j,k,l,tot2=c[t].size(),s;
fo(i,Ed[t-1]+1,Ed[t]) s=b[i],ans[s]-=f[q[s].z];
fo(i,0,tot2-1) ++f[c[t][i]];
for (i=ls[t]; i; i=a[i][1]) dfs(a[i][0]);
fo(i,Ed[t-1]+1,Ed[t]) s=b[i],ans[s]+=f[q[s].z];
}
void build(int x,int y,int tp)
{
clear(),len=1;
fo(i,x,y)
{
l=1;
fo(j,bg[i],ed[i])
{
New(l,st[j]-'a'),l=tr[l][st[j]-'a'];
if (tp) c[l].push_back(i);
}
if (!tp) ++f[l];
A[i]=l;
}
if (tp)
{
fo(i,1,Q)
{
for (j=1; j<=n; j+=S)
{
k=min(j+S-1,n);
if (!(q[i].x<=j && k<=q[i].y) || !bz[i])
fo(l,max(q[i].x,j),min(q[i].y,k)) ++Ed[A[l]];
}
}
fo(i,1,len) Ed[i]+=Ed[i-1];
fd(i,len+1,1) Ed[i]=Ed[i-1];
fo(i,1,Q)
{
for (j=1; j<=n; j+=S)
{
k=min(j+S-1,n);
if (!(q[i].x<=j && k<=q[i].y) || !bz[i])
{
fo(l,max(q[i].x,j),min(q[i].y,k))
b[++Ed[A[l]]]=i;
}
}
}
}
h=0,t=1;
d[1]=1;
while (h<t)
{
++h;
fo(i,0,25)
if (tr[d[h]][i])
{
l=tr[d[h]][i];
d[++t]=l;
j=fa[d[h]];
while (j && !tr[j][i]) j=fa[j];
fa[l]=(!j)?1:tr[j][i];
}
}
if (!tp)
{
fo(i,1,t)
f[d[i]]+=f[fa[d[i]]];
}
else
{
fo(i,2,len) NEW(fa[i],i);
dfs(1);
}
}
void js(int t,int id)
{
ll s=0;
if (Tm[t]==x) {ans[id]+=Ans[t];return;}
l=1;
fo(i,bg[t],ed[t])
{
while (l && !tr[l][st[i]-'a']) l=fa[l];
if (!l) l=1; else l=tr[l][st[i]-'a'];
s+=f[l];
}
Tm[t]=x,Ans[t]=s,ans[id]+=s;
}
};
int main()
{
#ifdef file
freopen("CF587F.in","r",stdin);
#endif
scanf("%d%d",&n,&Q),S=floor(sqrt(n));
fo(i,1,n)
{
scanf("%s",St+1),l=strlen(St+1);
bg[i]=len+1;
fo(j,1,l) st[++len]=St[j];
ed[i]=len;
}
fo(i,1,Q) scanf("%d%d%d",&q[i].x,&q[i].y,&q[i].z);
for (x=1; x<=n; x+=S)
{
y=min(x+S-1,n);
tree::build(x,y,0);
fo(i,1,Q)
if (q[i].x<=x && y<=q[i].y)
tree::js(q[i].z,i),bz[i]=1;
}
tree::build(1,n,1);
fo(i,1,Q) printf("%lld\n",ans[i]);
fclose(stdin);
fclose(stdout);
return 0;
}