题意
自己去看。。
题解
考虑AC自动机
然后分块
如果被询问串的长度是大于
n−−√
n
的,那么就对于每一个串一起错,每一次遍历整一颗树,统计一个前缀和,就可以做到
O(1)
O
(
1
)
回答了
否则,问题就就先变成r的答案减去l-1的答案
然后这样的话,就按照前缀排序就可以了
dfs一下,然后每一次就相当于子树加
我比较懒。。于是写了树状数组
复杂度是
nn−−√logn
n
n
l
o
g
n
实测,会被卡
怎么优化呢?
考虑每一次询问是
n−−√logn
n
l
o
g
n
的,但是修改是
logn
l
o
g
n
的
平衡复杂度,用分块来代替树状数组
就可以做到,询问
n−−√
n
,修改也是
n−−√
n
了,可以通过
最近要做的题比较多,就先不打了
放一个带log的做法
CODE:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<string>
using namespace std;
typedef long long LL;
const LL mx=200;
const LL N=100005*2;
LL n,q;
string ss[N];
struct qt
{
LL fail;
LL son[26];
}tr[N];LL nn=0;
struct qy
{
LL x,y,last;
}e[N];LL num,last[N];
LL pos[N];
LL len[N];
void init (LL x,LL y)
{
num++;
e[num].x=x;e[num].y=y;
e[num].last=last[x];
last[x]=num;
}
void Ins (LL x)
{
LL now=0;
len[x]=ss[x].size();
for (LL u=0;u<len[x];u++)
{
LL xx=ss[x][u]-'a';
if (tr[now].son[xx]==0) tr[now].son[xx]=++nn;
now=tr[now].son[xx];
}
pos[x]=now;
}
void bfs ()
{
queue<int> q;
q.push(0);
while (!q.empty())
{
LL x=q.front();q.pop();
for (LL u=0;u<26;u++)
{
LL son=tr[x].son[u],f=tr[x].fail;
if (son>0)
{
if (x==0) tr[son].fail=0;
else tr[son].fail=tr[f].son[u];
q.push(son);
}
else if (x!=0) tr[x].son[u]=tr[f].son[u];
}
}
for (LL u=1;u<=nn;u++) init(tr[u].fail,u);
}
struct qq
{
LL l,r,q,id;
}A[N],B[N];//小大
LL L[N],R[N],cnt;
LL tot,tot1;
LL ans[N];
bool cmp1 (qq x,qq y) {return x.q<y.q;}
LL o[N];
LL sum[N];
void bfs1 (LL x)
{
memset(sum,0,sizeof(sum));
LL now=0;
for (LL u=0;u<len[x];u++)
{
LL xx=ss[x][u]-'a';
now=tr[now].son[xx];
LL now1=now;
while (now1!=0) {sum[now1]++;now1=tr[now1].fail;}
}
}
void solveB ()
{
sort(B+1,B+1+tot1,cmp1);
LL now=0;
for (LL u=1;u<=tot1;u++)
{
if (now!=B[u].q)
{
now=B[u].q;
bfs1(now);
for (LL u=1;u<=n;u++) o[u]=o[u-1]+sum[pos[u]];
}
ans[B[u].id]=o[B[u].r]-o[B[u].l-1];
}
}
bool cmpA (qq a,qq b){return a.l<b.l;}
LL f[N];
LL lb (LL x){return x&(-x);}
LL get (LL x)
{
LL lalal=0;
while (x>=1) {lalal=lalal+f[x];x-=lb(x);}
return lalal;
}
void add (LL x,LL y) {while (x<=cnt) {f[x]+=y;x+=lb(x);}}
void solveA ()
{
sort(A+1,A+1+tot,cmpA);
LL now=0;
for (LL u=1;u<=tot;u++)
{
while (now<A[u].l) {now++;add(L[pos[now]],1);add(R[pos[now]]+1,-1);}
LL x=0;
LL h=A[u].q;
for (LL i=0;i<len[h];i++)
{
x=tr[x].son[ss[h][i]-'a'];
//printf("TKJ:%I64d %I64d %I64d\n",L[x],x,get(L[x]));
ans[A[u].id]=ans[A[u].id]+A[u].r*get(L[x]);
}
}
}
void dfs (LL x)
{
L[x]=++cnt;
for (LL u=last[x];u!=-1;u=e[u].last)
{
LL y=e[u].y;
dfs(y);
}
R[x]=cnt;
}
int main()
{
// freopen("a.in","r",stdin);
num=0;memset(last,-1,sizeof(last));
scanf("%I64d%I64d",&n,&q);
for (LL u=1;u<=n;u++)
{
cin>>ss[u];
Ins(u);
//printf("OZY:%I64d\n",pos[u]);
}
bfs();
for (LL u=1;u<=q;u++)
{
LL l,r,q;
scanf("%I64d%I64d%I64d",&l,&r,&q);
if (len[q]>=mx) {tot1++;B[tot1].l=l;B[tot1].r=r;B[tot1].id=u;B[tot1].q=q;}
else
{
if (l>1) {tot++;A[tot].l=l-1;A[tot].r=-1;A[tot].id=u;A[tot].q=q;}
tot++;A[tot].l=r;A[tot].r=1;A[tot].id=u;A[tot].q=q;
}
}
dfs(0);
solveA();
solveB();
for (LL u=1;u<=q;u++) printf("%I64d\n",ans[u]);
return 0;
}