题意:给一个字符串,多组查询,一些后缀两两的lcp长度和,查询个数和不超过1e6
题解:svt就是后缀虚树,suffix virtual tree,考虑后缀树lca求lcp长度,但是查询次数可能很多,不能每次遍历,所以要建出虚数后在虚树上dp,对于一个节点考虑算贡献,对于所有子树,两两算个数乘积乘上该点的长度即可
不会直接建后缀树= =,所以写了sam建后缀树
/**************************************************************
Problem: 3879
User: walfy
Language: C++
Result: Accepted
Time:28196 ms
Memory:252900 kb
****************************************************************/
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
//#pragma GCC optimize(4)
//#pragma GCC optimize("unroll-loops")
//#pragma comment(linker, "/stack:200000000")
//#pragma GCC optimize("Ofast,no-stack-protector")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#include<bits/stdc++.h>
#define fi first
#define se second
#define db double
#define mp make_pair
#define pb push_back
#define pi acos(-1.0)
#define ll long long
#define vi vector<int>
#define mod 1000000007
#define ld long double
#define C 0.5772156649
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define pli pair<ll,int>
#define pii pair<int,int>
//#define cd complex<double>
#define ull unsigned long long
#define base 1000000000000000000
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
#define fin freopen("a.txt","r",stdin)
#define fout freopen("b.txt","w",stdout)
#define fio ios::sync_with_stdio(false);cin.tie(0)
template<typename T>
inline T const& MAX(T const &a,T const &b){return a>b?a:b;}
template<typename T>
inline T const& MIN(T const &a,T const &b){return a<b?a:b;}
//inline void add(ll &a,ll b){a+=b;if(a>=mod)a-=mod;}
inline void sub(ll &a,ll b){a-=b;if(a<0)a+=mod;}
inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
inline ll qp(ll a,ll b){ll ans=1;while(b){if(b&1)ans=ans*a%mod;a=a*a%mod,b>>=1;}return ans;}
inline ll qp(ll a,ll b,ll c){ll ans=1;while(b){if(b&1)ans=ans*a%c;a=a*a%c,b>>=1;}return ans;}
using namespace std;
const double eps=1e-8;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int N=500000+10,maxn=3000000+10,inf=0x3f3f3f3f;
inline int read() {
char ch = getchar(); int x = 0, f = 1;
while(ch < '0' || ch > '9') {
if(ch == '-') f = -1;
ch = getchar();
} while('0' <= ch && ch <= '9') {
x = x * 10 + ch - '0';
ch = getchar();
} return x * f;
}
char s[N];
struct SAM{
int last,cnt;
int ch[N<<1][26],fa[N<<1],l[N<<1],pos[N<<1];
// bool val[N<<1];
inline void ins(int x,int po)
{
int p=last,np=++cnt;last=np;l[np]=l[p]+1;
pos[np]=po;//val[np]=1;
for(;p&&!ch[p][x];p=fa[p])ch[p][x]=np;
if(!p)fa[np]=1;
else
{
int q=ch[p][x];
if(l[q]==l[p]+1)fa[np]=q;
else
{
int nq=++cnt;l[nq]=l[p]+1;
memcpy(ch[nq],ch[q],sizeof ch[q]);
fa[nq]=fa[q];fa[q]=fa[np]=nq;pos[nq]=pos[q];
for(;ch[p][x]==q;p=fa[p])ch[p][x]=nq;
}
}
}
inline void build()
{
last=cnt=1;
int len=strlen(s+1);
for(int i=len;i>=1;i--)ins(s[i]-'a',i);
}
}sam;
//int ra[N],sa[N],tp;
struct suffixtree{
int id[N<<1];
struct edge{int to,Next;}ch[N<<1];
int cnt,head[N<<1];
void add(int u,int v)
{
ch[cnt].to=v;
ch[cnt].Next=head[u];
head[u]=cnt++;
}
inline void solve(int u)
{
// if(sam.val[u])sa[ra[sam.pos[u]]=++tp]=sam.pos[u];
for(int i=head[u];~i;i=ch[i].Next)solve(ch[i].to);
if(!id[sam.pos[u]])id[sam.pos[u]]=u;
}
inline void build()
{
cnt=0;
memset(head,-1,sizeof head);
for(int i=2;i<=sam.cnt;i++)
{
add(sam.fa[i],i);
// ch[sam.fa[i]][s[sam.pos[i]+sam.l[sam.fa[i]]]-'a']=i;
}
solve(1);
}
}suf;
int l[N<<1],deep[N<<1],res,fa[21][N<<1];
inline bool cmp(const int &a,const int &b){return l[a]<l[b];}
inline void dfs(int u,int dep)
{
l[u]=++res;deep[u]=dep;
for(int i=suf.head[u];~i;i=suf.ch[i].Next)
fa[0][suf.ch[i].to]=u,dfs(suf.ch[i].to,dep+1);
}
inline void gao()
{
for(int i=1;i<=20;i++)
for(int j=1;j<=sam.cnt;j++)
fa[i][j]=fa[i-1][fa[i-1][j]];
}
inline int lca(int x,int y)
{
if(deep[x]>deep[y])swap(x,y);
for(int i=20;i>=0;i--)
if(((deep[y]-deep[x])>>i)&1)
y=fa[i][y];
if(y==x)return x;
for(int i=20;i>=0;i--)
{
if(fa[i][x]!=fa[i][y])
{
x=fa[i][x];
y=fa[i][y];
}
}
return fa[0][x];
}
int st[N<<1],top,a[maxn],sz[N<<1];
bool vis[N<<1];
vi in;
struct edge{int to,Next;}e[N<<1];
int cnt,head[N<<1];
void init()
{
cnt=0;
memset(head,-1,sizeof head);
}
void add(int u,int v)
{
e[cnt].to=v;
e[cnt].Next=head[u];
head[u]=cnt++;
}
ll ans;
inline void add1(int a,int b){add(a,b);in.pb(a),in.pb(b);}
inline void ins(int x)
{
if(!top){st[++top]=x;return ;}
int lc=lca(st[top],x);
while(top>1&&deep[st[top-1]]>deep[lc])
add1(st[top-1],st[top]),top--;
if(top>=1&&deep[st[top]]>deep[lc])
add1(lc,st[top]),top--;
if(!top||deep[st[top]]<deep[lc])st[++top]=lc;
st[++top]=x;
}
inline void dfs1(int u)
{
sz[u]=0;
for(int i=head[u];~i;i=e[i].Next)
{
int x=e[i].to;
dfs1(x);
ans+=1ll*sz[x]*sz[u]*sam.l[u];
sz[u]+=sz[x];
}
if(vis[u])
{
ans+=1ll*sz[u]*sam.l[u];
sz[u]++;
}
}
inline void solve()
{
int k=read();
for(int i=0;i<k;i++)a[i]=read(),a[i]=suf.id[a[i]];
sort(a,a+k,cmp);
k=unique(a,a+k)-a;
top=0;ins(1);
for(int i=0;i<k;i++)
{
vis[a[i]]=1;
if(a[i]!=1)ins(a[i]);
}
while(top>=2)add1(st[top-1],st[top]),top--;
ans=0;dfs1(1);printf("%lld
",ans);
cnt=0;
for(int i=0;i<in.size();i++)head[in[i]]=-1;
for(int i=0;i<k;i++)vis[a[i]]=0;
in.clear();
}
int main()
{
// fin;fout;
int n=read(),m=read();
scanf("%s",s+1);
sam.build();
suf.build();
dfs(1,1);gao();
init();
while(m--)solve();
return 0;
}
/********************
10 1
abcdefghij
10
1 2 3 4 5 6 7 8 9 10
********************/