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 ...
随机推荐
- Solution -「洛谷 P5827」边双连通图计数
\(\mathcal{Description}\) link. 求包含 \(n\) 个点的边双连通图的个数. \(n\le10^5\). \(\mathcal{Solution}\) ...
- 分享一些访问之后显示本机公网ip的url地址
http://ip.42.pl/raw https://api.ip.sb/ip http://ip.3322.net http://ip.qaros.com http://ip.cip.cc htt ...
- Error from server error dialing backend remote error tls internal error
# kubectl exec -it mysql-master-8cfb64ff9-ct4dx -n prophet -- /bin/bash Error from server: error dia ...
- 在 CentOS 或 RHEL 系统上检查可用的安全更新的方法
当你更新系统时,根据你所在公司的安全策略,有时候可能只需要打上与安全相关的补丁.大多数情况下,这应该是出于程序兼容性方面的考量.那该怎样实践呢?有没有办法让 yum 只安装安全补丁呢? 答案是肯定的, ...
- 关于GDPR的六大理解
通用数据保护条例(GDPR)于2018年5月生效,根据法律条文,英国几乎所有企业都需要遵守该规定.然而,人们对法规本身及其对组织的意义仍存在一些误解.这可能会导致一些错误的决定. 通用数据保护条例(G ...
- Debian 11 配置优化指南
原文地址: Debian 11 配置优化指南 - WindSpiritIT 0x00 简介 本文仅适用于配置 Debian 11 Bullseye 文中同时包含 Gnome 桌面和 KDE 桌面配置, ...
- 60天shell脚本计划-8/12-渐入佳境
--作者:飞翔的小胖猪 --创建时间:2021年3月3日 --修改时间:2021年3月7日 说明 每日上传更新一个shell脚本,周期为60天.如有需求的读者可根据自己实际情况选用合适的脚本,也可在评 ...
- WIN10:删除开始菜单栏中的文件夹
C:\ProgramData\Microsoft\Windows\Start Menu\Programs,找到想删除的文件夹删除即可 其中ProgramData为隐藏文件夹,显示方式见下
- 含变量的字符串拼接(string.Format()或$"")
含变量的字符串拼接,一般不要用 + 来连接字符串,可用以下两种方式: 一.string.Format() 二.$"" (在C#6以上的版本中可用,推荐这种写法) 1 public ...
- 『现学现忘』Docker相关概念 — 8、虚拟化技术和容器技术的关系
目录 1.云计算中虚拟化技术和容器技术到的关系 2.虚拟机和容器对比 3.虚拟化技术和容器技术区别 1.云计算中虚拟化技术和容器技术到的关系 通过一个关于房间和住人的小问题,我们来初步的理解一下虚拟化 ...