对反串建SAM得到后缀树,两后缀的lcp就是其在后缀树上lca的len值,于是每次询问对后缀树建出虚树并统计答案即可。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 1000010
#define P 23333333333333333ll
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
int x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
int n,m,t,a[N*3],son[N][26],fail[N],deep[N],len[N],id[N],p[N],dfn[N],cnt=1,last=1;
struct data{int to,nxt;
}edge[N];
void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
char s[N];
void ins(int c)
{
int x=++cnt,p=last;last=x;len[x]=len[p]+1;id[len[x]]=x;
while (!son[p][c]) son[p][c]=x,p=fail[p];
if (!p) fail[x]=1;
else
{
int q=son[p][c];
if (len[p]+1==len[q]) fail[x]=q;
else
{
int y=++cnt;
len[y]=len[p]+1;
memcpy(son[y],son[q],sizeof(son[q]));
fail[y]=fail[q],fail[q]=fail[x]=y;
while (son[p][c]==q) son[p][c]=y,p=fail[p];
}
}
}
namespace euler_tour
{
int id[N<<1],LG2[N<<1],f[N<<1][22],cnt;
void dfs(int k)
{
dfn[k]=++cnt;id[cnt]=k;
for (int i=p[k];i;i=edge[i].nxt)
{
deep[edge[i].to]=deep[k]+1;
dfs(edge[i].to);
id[++cnt]=k;
}
}
void build()
{
dfs(1);
for (int i=1;i<=cnt;i++) f[i][0]=id[i];
for (int j=1;j<=21;j++)
for (int i=1;i<=cnt;i++)
if (deep[f[i][j-1]]<deep[f[min(cnt,i+(1<<j-1))][j-1]]) f[i][j]=f[i][j-1];
else f[i][j]=f[min(cnt,i+(1<<j-1))][j-1];
for (int i=2;i<=cnt;i++)
{
LG2[i]=LG2[i-1];
if ((2<<LG2[i])<=i) LG2[i]++;
}
}
int lca(int x,int y)
{
if (!x||!y) return 0;
x=dfn[x],y=dfn[y];
if (x>y) swap(x,y);
if (deep[f[x][LG2[y-x+1]]]<deep[f[y-(1<<LG2[y-x+1])+1][LG2[y-x+1]]]) return f[x][LG2[y-x+1]];
else return f[y-(1<<LG2[y-x+1])+1][LG2[y-x+1]];
}
}
using euler_tour::lca;
namespace virtual_tree
{
int p[N],size[N],stk[N],top,t;
bool flag[N];
ll ans;
struct data{int to,nxt;}edge[N];
void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
void newnode(int k,int x){if (!flag[k]) p[k]=0,flag[k]=1,size[k]=x;}
void build(int *a,int n)
{
stk[top=1]=1;newnode(1,0);t=0;
for (int i=1;i<=n;i++)
{
int l=lca(a[i],stk[top]);newnode(l,0);
while (top>1&&deep[stk[top-1]]>=deep[l]) addedge(stk[top-1],stk[top]),top--;
if (l!=stk[top]) addedge(l,stk[top]),stk[top]=l;
stk[++top]=a[i];newnode(a[i],1);
}
while (top) addedge(stk[top-1],stk[top]),top--;
}
void work(int k)
{
flag[k]=0;
for (int i=p[k];i;i=edge[i].nxt)
{
work(edge[i].to);
ans=(ans+1ll*size[k]*size[edge[i].to]*len[k])%P;
size[k]+=size[edge[i].to];
}
}
ll calc()
{
ans=0;
work(1);
return ans;
}
}
bool cmp(const int&x,const int&y)
{
return dfn[x]<dfn[y];
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
const char LL[]="%I64d\n";
#else
const char LL[]="%lld\n";
#endif
n=read(),m=read();
scanf("%s",s+1);
for (int i=1;i<=n;i++) ins(s[n-i+1]-'a');
for (int i=2;i<=cnt;i++) addedge(fail[i],i);
euler_tour::build();
while (m--)
{
t=read();for (int i=1;i<=t;i++) a[i]=id[n-read()+1];
sort(a+1,a+t+1,cmp);t=unique(a+1,a+t+1)-a-1;
virtual_tree::build(a,t);
printf(LL,virtual_tree::calc());
}
return 0;
}

  

BZOJ3879 SvT(后缀树+虚树)的更多相关文章

  1. bzoj3879 SvT(后缀自动机+虚树)

    bzoj3879 SvT(后缀自动机+虚树) bzoj 有一个长度为n的仅包含小写字母的字符串S,下标范围为[1,n]. 现在有若干组询问,对于每一个询问,我们给出若干个后缀(以其在S中出现的起始位置 ...

  2. 仙人掌 && 圆方树 && 虚树 总结

    仙人掌 && 圆方树 && 虚树 总结 Part1 仙人掌 定义 仙人掌是满足以下两个限制的图: 图完全联通. 不存在一条边处在两个环中. 其中第二个限制让仙人掌的题做 ...

  3. [SDOI2018]战略游戏(圆方树+虚树)

    喜闻乐见的圆方树+虚树 图上不好做,先建出圆方树. 然后答案就是没被选到的且至少有两条边可以走到被选中的点的圆点的数量. 语文不好,但结论画画图即可得出. 然后套路建出虚树. 发现在虚树上DP可以得出 ...

  4. CF1073G Yet Another LCP Problem 后缀自动机 + 虚树 + 树形DP

    题目描述 记 $lcp(i,j)$ 表示 $i$ 表示 $i$ 这个后缀和 $j$ 这个后缀的最长公共后缀长度给定一个字符串,每次询问的时候给出两个正整数集合 $A$ 和 $B$,求$\sum_{i\ ...

  5. hihoCoder #1954 : 压缩树(虚树)

    题意 有一棵 \(n\) 个节点且以 \(1\) 为根的树,把它复制成 \(m\) 个版本,有 \(q\) 次操作,每次对 \([l, r]\) 这些版本的 \(v\) 节点到根的路径收缩起来. 收缩 ...

  6. 51Nod1868 彩色树 虚树

    原文链接https://www.cnblogs.com/zhouzhendong/p/51Nod1868.html 题目传送门 - 51Nod1868 题意 给定一颗 $n$个点的树,每个点一个 $[ ...

  7. Codechef Sad Pairs——圆方树+虚树+树上差分

    SADPAIRS 删点不连通,点双,圆方树 非割点:没有影响 割点:子树DP一下 有不同颜色,所以建立虚树 在圆方树上dfs时候 如果当前点是割点 1.统计当前颜色虚树上的不连通点对,树形DP即可 2 ...

  8. BZOJ5329:[SDOI2018]战略游戏(圆方树,虚树)

    Description 省选临近,放飞自我的小Q无心刷题,于是怂恿小C和他一起颓废,玩起了一款战略游戏. 这款战略游戏的地图由n个城市以及m条连接这些城市的双向道路构成,并且从任意一个城市出发总能沿着 ...

  9. Luogu P4606 [SDOI2018] 战略游戏 圆方树 虚树

    https://www.luogu.org/problemnew/show/P4606 把原来的图的点双联通分量缩点(每个双联通分量建一个点,每个割点再建一个点)(用符合逻辑的方式)建一棵树(我最开始 ...

随机推荐

  1. spring bean 的作用域之间有什么区别

    spring bean 的作用域之间有什么区别? spring容器中的bean可以分为五个范围.所有范围的名称都是说明的, 1.singleton:这种bean范围是默认的,这种范围确保不管接受到多个 ...

  2. 2018-2019-2 20165234 《网络对抗技术》 Exp9 Web安全基础

    Exp9 Web安全基础 一. 实践内容 1. 安装JDK.Webgoat 2. SQL注入攻击 数字型注入(Numeric SQL Injection) 日志欺骗(Log Spoofing) 字符串 ...

  3. android studio: 9:57 Unsupported Modules Detected: Compilation is not supported for following modules: map, app, ota, MediaEditor, rcLcmSercive, DroneSDK, qrcodelibrary, rcService, speechService. Unfo

    Android studio Error “Unsupported Modules Detected: Compilation is not supported for following modul ...

  4. git notes的使用

    1. 获取notes git fetch origin refs/notes/*:refs/notes/* 2. 设置notes 2.1 git config --add core.notesRef ...

  5. Django中验证码的登录

    需求概述 一般登录页面或者其他页面都需要验证码的功能,那在Django中如何实现呢? 这基本就需要用到第三方模块了:pillow 还需要两个文件,一个是字体文件:Monaco.ttf,另一个是一个模块 ...

  6. Delphi 中记录类型 给记录指针赋值

    PPersion=^TPersion; TPersion=packed record Name:string; Sex:string; Clasee:string; end; var persion: ...

  7. 【创业】2B创业历程

    http://www.woshipm.com/chuangye/2800111.html http://www.woshipm.com/chuangye/2803240.html http://www ...

  8. (二)UML之类图、接口、包

    一.概念 类图(Class Diagram): 类图是面向对象系统建模中最常用和最重要的图,是定义其它图的基础.类图主要是用来显示系统中的类.接口以及它们之间的静态结构和关系的一种静态模型. 类图的3 ...

  9. ELK之elasticsearch插件导致filebeat没有上传日志至elasticsearch解决办法

    使用filebeat收集nginx发现日志为上传,elasticsearch没有日志,kibana没有展示 查看filebeat日志 日志目录为/var/log/filebeat  下面有多个日志文件 ...

  10. 纯js脚本操作excel

    纯js脚本解析excel,并渲染为htm表格,投放大屏并滚动! 代码:https://github.com/tianbogit/js_excel