bzoj3879 SvT(后缀自动机+虚树)
bzoj3879 SvT(后缀自动机+虚树)
有一个长度为n的仅包含小写字母的字符串S,下标范围为[1,n].
现在有若干组询问,对于每一个询问,我们给出若干个后缀(以其在S中出现的起始位置来表示),求这些后缀两两之间的LCP(LongestCommonPrefix)的长度之和.一对后缀之间的LCP长度仅统计一遍.
题解时间
完 全 一 致
只不过这个是只选中其中一部分后缀。
bzoj3238可以用SA搞也可以用SAM搞。
这题一样,但是SAM好想。
建完SAM每次询问建虚树,之后和上面那道全统计一样,一个点的贡献为 $ len[x] * \Sigma_{v1,v2} size_{v1} * size_{v2} $ 。
#include<bits/stdc++.h>
using namespace std;
typedef long long lint;
template<typename TP>inline void read(TP &tar)
{
TP ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){ret=ret*10+ch-'0';ch=getchar();}
tar=ret*f;
}
namespace RKK
{
const int N=1000011;
int len,qaq;char str[N];int ip[N];
struct sumireko{int to,ne;}e[N];int he[N],ecnt;
void addline(int f,int t){e[++ecnt].to=t;e[ecnt].ne=he[f],he[f]=ecnt;}
struct remilia{int tranc[26],len,pre;}s[N];
int fin=1,size=1;
void ins(int ch)
{
int npx,npy,lpx,lpy;
npx=++size,lpx=fin,s[npx].len=s[lpx].len+1;
for(;lpx&&!s[lpx].tranc[ch];lpx=s[lpx].pre) s[lpx].tranc[ch]=npx;
if(!lpx) s[npx].pre=1;
else
{
lpy=s[lpx].tranc[ch];
if(s[lpy].len==s[lpx].len+1) s[npx].pre=lpy;
else
{
npy=++size;
s[npy]=s[lpy],s[npy].len=s[lpx].len+1;
s[npx].pre=s[lpy].pre=npy;
while(s[lpx].tranc[ch]==lpy)
s[lpx].tranc[ch]=npy,lpx=s[lpx].pre;
}
}
fin=npx;
}
int sp[N],ep[N],fa[N],top[N],dep[N],sz[N],dson[N],da;
void dfs(int x)
{
sz[x]=1;
for(int i=he[x],t=e[i].to;i;i=e[i].ne,t=e[i].to)
fa[t]=x,dep[t]=dep[x]+1,dfs(t),sz[x]+=sz[t],dson[x]=(sz[t]>sz[dson[x]]?t:dson[x]);
}
void dfs(int x,int tp)
{
top[x]=tp,sp[x]=++da;
if(dson[x]) dfs(dson[x],tp);
for(int i=he[x],t=e[i].to;i;i=e[i].ne,t=e[i].to)if(t!=dson[x])
dfs(t,t);
ep[x]=da;
}
int lca(int x,int y)
{
while(top[x]!=top[y]) dep[top[x]]>dep[top[y]]?x=fa[top[x]]:y=fa[top[y]];
return dep[x]<dep[y]?x:y;
}
lint ans;
bool use[N];
int work(int x)
{
int sx=use[x];
for(int i=he[x],t=e[i].to,st;i;i=e[i].ne,t=e[i].to)
st=work(t),ans+=1ll*s[x].len*sx*st,sx+=st;
return sx;
}
int lst[N],ln;
int sta[N],stp;
bool cmp(const int &a,const int &b){return sp[a]<sp[b];}
int Iris()
{
scanf("%d%d%s",&len,&qaq,str+1);
for(int i=len;i;i--) ins(str[i]-'a'),ip[i]=fin;
for(int i=2;i<=size;i++) addline(s[i].pre,i);
dfs(1),dfs(1,1);memset(he,0,sizeof(he)),ecnt=0;
for(int rkk=1;rkk<=qaq;rkk++)
{
read(ln),stp=0,ans=0;for(int i=1,x;i<=ln;i++) read(x),lst[i]=ip[x],use[lst[i]]=1;
sort(lst+1,lst+1+ln,cmp);
for(int i=1,lim=ln;i<lim;i++) lst[++ln]=lca(lst[i],lst[i+1]);
sort(lst+1,lst+1+ln,cmp),ln=unique(lst+1,lst+1+ln)-lst-1;
for(int i=1;i<=ln;i++)
{
while(stp&&ep[sta[stp]]<sp[lst[i]]) stp--;
addline(sta[stp],lst[i]),sta[++stp]=lst[i];
}
work(lst[1]),printf("%lld\n",ans);
for(int i=1;i<=ln;i++) use[lst[i]]=0,he[lst[i]]=0;ecnt=0;
}
return 0;
}
}
int main(){return RKK::Iris();}
bzoj3879 SvT(后缀自动机+虚树)的更多相关文章
- CF1073G Yet Another LCP Problem 后缀自动机 + 虚树 + 树形DP
题目描述 记 $lcp(i,j)$ 表示 $i$ 表示 $i$ 这个后缀和 $j$ 这个后缀的最长公共后缀长度给定一个字符串,每次询问的时候给出两个正整数集合 $A$ 和 $B$,求$\sum_{i\ ...
- BZOJ3413: 匹配(后缀自动机 线段树合并)
题意 题目链接 Sol 神仙题Orz 后缀自动机 + 线段树合并... 首先可以转化一下模型(想不到qwq):问题可以转化为统计\(B\)中每个前缀在\(A\)中出现的次数.(画一画就出来了) 然后直 ...
- cf666E. Forensic Examination(广义后缀自动机 线段树合并)
题意 题目链接 Sol 神仙题Orz 后缀自动机 + 线段树合并 首先对所有的\(t_i\)建个广义后缀自动机,这样可以得到所有子串信息. 考虑把询问离线,然后把\(S\)拿到自动机上跑,同时维护一下 ...
- 洛谷P2178 [NOI2015]品酒大会(后缀自动机 线段树)
题意 题目链接 Sol 说一个后缀自动机+线段树的无脑做法 首先建出SAM,然后对parent树进行dp,维护最大次大值,最小次小值 显然一个串能更新答案的区间是\([len_{fa_{x}} + 1 ...
- BZOJ1396: 识别子串(后缀自动机 线段树)
题意 题目链接 Sol 后缀自动机+线段树 还是考虑通过每个前缀的后缀更新答案,首先出现次数只有一次,说明只有\(right\)集合大小为\(1\)的状态能对答案产生影响 设其结束位置为\(t\),代 ...
- [Luogu5161]WD与数列(后缀数组/后缀自动机+线段树合并)
https://blog.csdn.net/WAautomaton/article/details/85057257 解法一:后缀数组 显然将原数组差分后答案就是所有不相交不相邻重复子串个数+n*(n ...
- 洛谷P4493 [HAOI2018]字串覆盖(后缀自动机+线段树+倍增)
题面 传送门 题解 字符串就硬是要和数据结构结合在一起么--\(loj\)上\(rk1\)好像码了\(10k\)的样子-- 我们设\(L=r-l+1\) 首先可以发现对于\(T\)串一定是从左到右,能 ...
- luogu5212/bzoj2555 substring(后缀自动机+动态树)
对字符串构建一个后缀自动机. 每次查询的就是在转移边上得到节点的parent树中后缀节点数量. 由于强制在线,可以用动态树维护后缀自动机parent树的子树和. 注意一个玄学的优化:每次在执行连边操作 ...
- 模板—字符串—后缀自动机(后缀自动机+线段树合并求right集合)
模板—字符串—后缀自动机(后缀自动机+线段树合并求right集合) Code: #include <bits/stdc++.h> using namespace std; #define ...
随机推荐
- Back to Basics: RAII and The Rule of Zero
本文整理了Arthur O'Dwyer在CppCon 2019上关于RAII的演讲,演讲的slides可以在此链接进行下载. 在C++程序中,我们往往需要管理各种各样的资源.资源通常包括以下几种: A ...
- 命令行与C++
windows和Linux都接受使用命令行进行程序的运行,例如在windows下使用命令行命令.\notepad可以打开记事本,使用特定的命令行参数,如.\notepad 1.txt可以打开1.txt ...
- WEB服务蜜罐部署实验
实验目的 了解WEB蜜罐的基本原理,掌握Trap Server的使用. 实验原理 Trap Server是一款WEB服务器蜜罐软件,它可以模拟很多不同的服务器,例如Apache. HTTP Serve ...
- 一文带你盘点市场上主流的BI产品主要有哪些
随着时代的发展,商业智能使数据分析和数据可视化的门槛不断降低,使得企业各级人员都能进行数据分析,从而加深业务洞察,推动企业发展.而在数据分析领域,BI产品发挥了十分重要的作用. 市场需求变化日益频繁 ...
- 做PPT必备的大数据分析网站,好看又免费的报表工具
小明以前是学技术,跳槽来到一家大公司,在这个公司里会经常开会,比如有月度报告.季度报告以及年度报告,在开会前小明了解到同事们都会制作精美的PPT来汇报工作计划和目标,看到同事们精美的PPT里各种好看的 ...
- 【C# 编码格式】 System.Text 命名空间 Encoding
Encoding基类 System.Text.ASCIIEncoding类 System.Text.UnicodeEncoding类 System.Text.UTF32Encodin ...
- Hadoop权威指南 - 学习笔记
初识Hadoop.关于MapReduce Hadoop宏观介绍 相对于其他系统的优势 关系型数据库管理系统 为什么不能用配有大量硬盘的数据库进行大规模分析?为什么需要Hadoop? 因为计算机硬盘的发 ...
- Java课程设计---项目数据库设计(含实体类)
1.表设计 (1)新建表tb_student(学生表) (2)新建表tb_admin(管理员表) (3)新建表tb_teacher(教师表) (4)新建表tb_course(课程表) (5)新建表tb ...
- VMware:用Ubuntu创建一个新的虚拟机
1)进入VMware,选择创建新虚拟机 2)安装ISO文件 3)各种名,密码 这里有可能出错: 原因是你输入的用户名和系统用户名重复了,修改一下就可以了 4)安装位置:这里可以是任意盘,但至少要有4G ...
- C# Md5Hash
/// <summary> /// MD5 32位加密(大写) /// </summary> /// <param name="str">< ...