一、题目
二、解法
先对原串的反串建后缀自动机,然后两个后缀的就是它们在自动机上的长度。
然后就可以在后缀自动机,设为子树内集合元素个数,意义差不多,那么答案就可以这样算:
注意此时没把本节点是不是集合元素算进去,所以还要继续算贡献:
然后这道题给的询问很多,但是关键点总数是确定的,显然是虚树优化。
思路到此就讲完了,时间复杂度,注意虚树的数组不能开小(我调了一个小时),然后就是不要写在结构体里面,更多细节看我的代码吧。
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <stack>
using namespace std;
const int M = 400005;
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,m,k;char s[M];
int p[M][20],dep[M],dfin[M],dfou[M];
struct edge
{
int v,next;
edge(int V=0,int N=0) : v(V) , next(N) {}
};
bool cmp(int x,int y)
{
int t1=x>0?dfin[x]:dfou[-x];
int t2=y>0?dfin[y]:dfou[-y];
return t1<t2;
}
struct automaton
{
int n,cnt,last,len[M],fa[M],ch[M][26],tr[M];
int k,k1,A,B,t[M<<1],vis[M],a[M],b[M],sa[M],sb[M];
edge e[2*M];int Index,tot,f[M];long long ans;
stack<int> s;vector<int> G[M];
automaton() {cnt=last=1;}
void add(int c)
{
int p=last,np=last=++cnt;
len[np]=len[p]+1;
for(;p && !ch[p][c];p=fa[p]) ch[p][c]=np;
if(!p) fa[np]=1;
else
{
int q=ch[p][c];
if(len[q]==len[p]+1) fa[np]=q;
else
{
int nq=++cnt;
fa[nq]=fa[q];
memcpy(ch[nq],ch[q],sizeof ch[q]);
len[nq]=len[p]+1;
fa[q]=fa[np]=nq;
for(;p && ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
}
}
tr[++n]=last;
}
void dfs1(int u)
{
p[u][0]=fa[u];
dep[u]=dep[fa[u]]+1;
for(int i=1;i<20;i++)
p[u][i]=p[p[u][i-1]][i-1];
dfin[u]=++Index;
for(int i=f[u];i;i=e[i].next)
if(e[i].v^fa[u])
dfs1(e[i].v);
dfou[u]=++Index;
}
void build()
{
for(int i=2;i<=cnt;i++)
{
e[++tot]=edge(fa[i],f[i]),f[i]=tot;
e[++tot]=edge(i,f[fa[i]]),f[fa[i]]=tot;
}
dfs1(1);
}
int get(int u,int v)
{
if(dep[u]<=dep[v]) swap(u,v);
for(int i=19;i>=0;i--)
if(dep[p[u][i]]>=dep[v])
u=p[u][i];
if(u==v) return u;
for(int i=19;i>=0;i--)
if(p[u][i]^p[v][i])
u=p[u][i],v=p[v][i];
return p[u][0];
}
void dfs2(int u,int fa)
{
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(v^fa)
dfs2(v,u),sa[u]+=sa[v],sb[u]+=sb[v];
}
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(v^fa)
{
ans+=1ll*(sa[u]-sa[v])*sb[v]*len[u];
a[v]=b[v]=sa[v]=sb[v]=vis[v]=0;
G[v].clear();
}
}
ans+=(1ll*a[u]*b[u]+1ll*a[u]*sb[u]+1ll*b[u]*sa[u])*len[u];
sa[u]+=a[u];sb[u]+=b[u];
}
void solve()
{
k=ans=0;
A=read();B=read();
for(int i=1;i<=A;i++)
{
t[++k]=tr[n-read()+1];
vis[t[k]]=1;a[t[k]]++;
}
for(int i=1;i<=B;i++)
{
int x=tr[n-read()+1];
if(!vis[x]) t[++k]=x,vis[x]=1;
b[x]++;
}
sort(t+1,t+1+k,cmp);
k1=k;
for(int i=1;i<k1;i++)
{
int tmp=get(t[i],t[i+1]);
if(!vis[tmp]) t[++k]=tmp,vis[tmp]=1;
}
if(!vis[1]) t[++k]=1,vis[1]=1;
k1=k;
for(int i=1;i<=k1;i++)
t[++k]=-t[i];
sort(t+1,t+1+k,cmp);
for(int i=1;i<=k;i++)
{
if(t[i]>0) s.push(t[i]);
else
{
int x=s.top();s.pop();
if(x==1) break;
G[x].push_back(s.top());
G[s.top()].push_back(x);
}
}
dfs2(1,0);
printf("%lld\n",ans);
vis[1]=sa[1]=sb[1]=a[1]=b[1]=0;
G[1].clear();
}
}Sam;
int main()
{
n=read();m=read();
scanf("%s",s);
for(int i=n-1;i>=0;i--)
Sam.add(s[i]-'a');
Sam.build();
while(m--)
Sam.solve();
}
来源:CSDN
作者:C202044zxy
链接:https://blog.csdn.net/C202044zxy/article/details/104221341