【BZOJ3879】SvT(后缀自动机,虚树)
【BZOJ3879】SvT(后缀自动机,虚树)
题面
题解
看着这个东西,询问若干个前缀两两之间的\(lcp\)?
显然\(lcp\)就是\(SAM\)构建出来的\(parent\)数上的\(LCA\)所代表的长度。
那么这样子就转为了树型\(dp\)。
然后发现是前缀?把串转过来就是后缀了。
\(\sum t\)是\(O(n)\)级别的?显然虚树。
那么直接虚树搞搞就好了。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAX 1010000
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
int n,m;char ch[MAX];
long long ans;
struct Node
{
int son[26];
int len,ff;
}t[MAX];
int last=1,tot=1,lt[MAX];
void extend(int c)
{
int p=last,np=++tot;last=tot;
t[np].len=t[p].len+1;
while(p&&!t[p].son[c])t[p].son[c]=np,p=t[p].ff;
if(!p)t[np].ff=1;
else
{
int q=t[p].son[c];
if(t[q].len==t[p].len+1)t[np].ff=q;
else
{
int nq=++tot;
t[nq]=t[q];t[nq].len=t[p].len+1;
t[q].ff=t[np].ff=nq;
while(p&&t[p].son[c]==q)t[p].son[c]=nq,p=t[p].ff;
}
}
}
struct Line{int v,next;}e[MAX];
int h[MAX],cnt=1;
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
int dfn[MAX],low[MAX],dep[MAX],fa[MAX],tim,size[MAX],hson[MAX],top[MAX];
void dfs1(int u,int ff)
{
size[u]=1;dep[u]=dep[ff]+1;fa[u]=ff;
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v;
dfs1(v,u);size[u]+=size[v];
if(size[v]>size[hson[u]])hson[u]=v;
}
}
void dfs2(int u,int tp)
{
dfn[u]=++tim;top[u]=tp;
if(hson[u])dfs2(hson[u],tp);
for(int i=h[u];i;i=e[i].next)
if(e[i].v!=hson[u])dfs2(e[i].v,e[i].v);
low[u]=tim;
}
int LCA(int u,int v)
{
while(top[u]^top[v])(dep[top[u]]<dep[top[v]])?v=fa[top[v]]:u=fa[top[u]];
return dep[u]<dep[v]?u:v;
}
int p[MAX],S[MAX];
bool vis[MAX];
bool cmp(int a,int b){return dfn[a]<dfn[b];}
int dp(int u)
{
int ret=0;if(vis[u])ret=1;
for(int i=h[u];i;i=e[i].next)
{
int d=dp(e[i].v);
ans+=1ll*t[u].len*d*ret;
ret+=d;
}
return ret;
}
int main()
{
n=read();m=read();
scanf("%s",ch+1);reverse(&ch[1],&ch[n+1]);
for(int i=1;i<=n;++i)extend(ch[i]-97),lt[i]=last;
for(int i=1;i<=tot;++i)if(t[i].ff)Add(t[i].ff,i);
dfs1(1,0);dfs2(1,1);memset(h,0,sizeof(h));cnt=1;
while(m--)
{
int t=read(),top=0;cnt=0;
for(int i=1;i<=t;++i)vis[p[i]=lt[n-read()+1]]=true;
sort(&p[1],&p[t+1],cmp);
for(int i=t;i>1;--i)p[++t]=LCA(p[i],p[i-1]);
sort(&p[1],&p[t+1],cmp);t=unique(&p[1],&p[t+1])-p-1;
for(int i=1;i<=t;++i)
{
while(top&&low[S[top]]<dfn[p[i]])--top;
Add(S[top],p[i]);S[++top]=p[i];
}
ans=0;dp(p[1]);printf("%lld\n",ans);
for(int i=1;i<=t;++i)h[p[i]]=0,vis[p[i]]=false;
}
return 0;
}
【BZOJ3879】SvT(后缀自动机,虚树)的更多相关文章
- bzoj3879 SvT(后缀自动机+虚树)
bzoj3879 SvT(后缀自动机+虚树) bzoj 有一个长度为n的仅包含小写字母的字符串S,下标范围为[1,n]. 现在有若干组询问,对于每一个询问,我们给出若干个后缀(以其在S中出现的起始位置 ...
- 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 ...
随机推荐
- Java 中单引号和双引号的区别
引自:https://blog.csdn.net/hubianyu/article/details/39700367 单引号引的数据 是char类型的 双引号引的数据 是String类型的char定义 ...
- 系统引导修复,grub2下的各种骚作
新买的xps装了一个rhel7.5,各种恶心... 第一次:升级内核之后居然引导不了! 进入bios setup,把bios 引导的文件选择为 grub64.eif,成功进入系统 第二次:升级grub ...
- vue-cli 3.0 axios 跨域请求代理配置及生产环境 baseUrl 配置
1. 开发环境跨域配置 在 vue.config.js 文件中: module.exports = { runtimeCompiler: true, publicPath: '/', // 设置打包文 ...
- ubuntu在指定的文件夹下创建python3和python2的虚拟环境
1.用pip安装virtualenv sudo apt-get install python-virtualenv 2.创建python2和python3虚拟环境 2.1 创建python2的虚拟环境 ...
- JVM规范系列第3章:为Java虚拟机编译
Oracle 的 JDK 包括两部分内容:一部分是将 Java 源代码编译成 Java 虚拟机的指令集的编译器,另一部分是用于Java 虚拟机的运行时环境. 第一部分应该说的是 Javac 这个前置编 ...
- centos7.2部署vnc服务记录
不做过多介绍了,下面直接记录下centos7系统下安装配置vncserver的操作记录 0)更改为启动桌面或命令行模式 获取当前系统启动模式 [root@localhost ~]# systemctl ...
- git 配置别名
对于常用的git的命令,可以通过配置别名的方式,提高工作效率. $ git config --global alias.co checkout //执行git co 相当于git checkout $ ...
- JS进阶系列之执行上下文
function test(){ console.log(a);//undefined; var a = 1; } test(); 也许你会遇到过上面这样的面试题,你只知道它考的是变量提升,但是具体的 ...
- 第三周作业————————word count
#include <stdio.h> void main() { FILE *fp; , str, word, pu, ch; int g; str = ; word = ; pu = ; ...
- beta阶段测试基本概况对应机型硬件信息
机型测试概况 测试结果 测试终端数 品牌分布分析 系统分布分析 分辨率分布 未执行 1 联想 4.0.3 480*800 安装失败 1 联想 4.2.1 480*854 通过 119 华为, 三星, ...