题意:给一个串 SSS,qqq 次询问,每次给定串 TTT 和 l,rl,rl,r ,求有多少个本质不同的串是 TTT 的子串而不是 Sl…rS_{l\dots r}Sl…r​ 的子串。

∣S∣≤5×105,q≤105,∑∣T∣≤106|S|\leq 5\times 10^5,q\leq 10^5,\sum|T|\leq 10^6∣S∣≤5×105,q≤105,∑∣T∣≤106

先考虑所有询问 l=1,r=∣S∣l=1,r=|S|l=1,r=∣S∣ 怎么做。

先对 SSS 建个 SAM 出来,我们需要把每次询问的 TTT 放上去搞搞。如果用广义后缀自动机的话复杂度是和 SSS 有关的,做不了。所以要把 TTT 就看成一个串。

考虑把 TTT 放上去匹配,从 SAM 上的当前点不断跳 fail 直到有对应的转移边。这样可以得到 TTT 的每一个前缀 [1,i][1,i][1,i] 最长的 在 SSS 中出现过的 后缀长度,记为 lenilen_ileni​。

但我们要求的是本质不同的串,还需要把上面那个东西去重。

我们一次加入 TTT 的每个字符,那么当前的一个后缀合法当且仅当其长度大于 lenilen_ileni​。我们可以对 TTT 再单独建一个 SAM,维护每个结点 endpos 集合中的最大值,然后遍历每个结点统计答案即可。

然后对于 l,rl,rl,r 任意的情况,就是用可持久化线段树合并来显式维护 endpos 集合。

然后就是一通乱搞。

冷静分析一下,我们要做的是当前维护的串是否在 Sl…rS_{l\dots r}Sl…r​ 中出现过,也就是 [l+s−1,r][l+s-1,r][l+s−1,r] 中有没有这个点的 endpos 集合中的位置,其中 sss 为当前串长度。直接暴力丢掉第一个字符,如果当前结点丢完了再跳父亲。转移的时候额外判一下要去的结点对应区间有没有这个点的 endpos。

因为这个串可能被砍了一半,所以在更新 lenilen_ileni​ 的时候要在 [l,r][l,r][l,r] 里查一个 endpos 的最大值 mxmxmx,和 mx−l+1mx-l+1mx−l+1 取 min⁡\minmin。

复杂度 O(nlog⁡n)\Omicron(n\log n)O(nlogn)

#include <iostream>
#include <cstring>
#include <cctype>
#include <cstdio>
#define MAXN 2000005
using namespace std;
typedef long long ll;
int ch[MAXN<<4][2],sum[MAXN<<4],mxpos[MAXN<<4],cnt;
void modify(int& x,int l,int r,int k)
{if (!x) x=++cnt;++sum[x];if (l==r) return (void)(mxpos[x]=l);int mid=(l+r)>>1;if (k<=mid) modify(ch[x][0],l,mid,k);else modify(ch[x][1],mid+1,r,k);mxpos[x]=max(mxpos[ch[x][0]],mxpos[ch[x][1]]);
}
int merge(int x,int y)
{if (!x||!y) return x|y;int p=++cnt;ch[p][0]=ch[x][0],ch[p][1]=ch[x][1];ch[p][0]=merge(ch[p][0],ch[y][0]);ch[p][1]=merge(ch[p][1],ch[y][1]);sum[p]=sum[ch[p][0]]+sum[ch[p][1]];mxpos[p]=max(mxpos[ch[p][0]],mxpos[ch[p][1]]);return p;
}
int query(int x,int l,int r,int ql,int qr)
{if (!x) return 0;if (ql<=l&&r<=qr) return sum[x];if (qr<l||r<ql) return 0;int mid=(l+r)>>1;return query(ch[x][0],l,mid,ql,qr)+query(ch[x][1],mid+1,r,ql,qr);
}
int querymax(int x,int l,int r,int ql,int qr)
{if (!x) return 0;if (ql<=l&&r<=qr) return mxpos[x];if (qr<l||r<ql) return 0;int mid=(l+r)>>1;return max(querymax(ch[x][0],l,mid,ql,qr),querymax(ch[x][1],mid+1,r,ql,qr));
}
int a[MAXN],c[MAXN],pos[MAXN],n,m;
char s[MAXN],t[MAXN];
struct SAM
{int ch[MAXN][26],fa[MAXN],len[MAXN],rt[MAXN],mx[MAXN],las,tot;inline void insert(int c,int k,int type){int cur=++tot;int p=las;len[cur]=len[p]+1;for (;p&&!ch[p][c];p=fa[p]) ch[p][c]=cur;if (!p) fa[cur]=1;else{int q=ch[p][c];if (len[q]==len[p]+1) fa[cur]=q;else{int _q=++tot;len[_q]=len[p]+1;fa[_q]=fa[q],fa[q]=fa[cur]=_q;memcpy(ch[_q],ch[q],sizeof(ch[_q]));for (;ch[p][c]==q;p=fa[p]) ch[p][c]=_q;}}las=cur;if (type) modify(rt[cur],1,n,k);else mx[cur]=k;}inline void build(int type){for (int i=1;i<=tot;i++) c[i]=0;for (int i=1;i<=tot;i++) ++c[len[i]];for (int i=1;i<=tot;i++) c[i]+=c[i-1];for (int i=1;i<=tot;i++) a[c[len[i]]--]=i;for (int i=tot;i>=1;i--) if (fa[a[i]]) {if (type) rt[fa[a[i]]]=merge(rt[fa[a[i]]],rt[a[i]]);else mx[fa[a[i]]]=max(mx[fa[a[i]]],mx[a[i]]);              }}inline void query(int l,int r){int cur=1,s=0,p=0;for (int i=1;i<=m;i++){while (cur>1&&(!ch[cur][t[i]-'a']||l+s-1>r||!::query(rt[ch[cur][t[i]-'a']],1,n,l+max(s,1)-1,r)))((--s)==len[fa[cur]])&&(cur=fa[cur]);(::query(rt[ch[cur][t[i]-'a']],1,n,l+max(s,1)-1,r))&&(cur=ch[cur][t[i]-'a'],++s,++p);pos[i]=max(0,min(s,querymax(rt[cur],1,n,l,r)-l+1));}}inline ll calc(){ll ans=0;for (int i=1;i<=tot;i++) ans+=max(0,len[i]-max(len[fa[i]],pos[mx[i]]));return ans;}inline void clear(){for (int i=1;i<=tot;i++) mx[i]=fa[i]=0,memset(ch[i],0,sizeof(ch[i]));las=tot=1;}inline SAM():las(1),tot(1){}
}S,T;
int main()
{scanf("%s",s+1);n=strlen(s+1);for (int i=1;i<=n;i++) S.insert(s[i]-'a',i,1);S.build(1);int q;scanf("%d",&q);while (q--){scanf("%s",t+1);m=strlen(t+1);for (int i=1;i<=m;i++) T.insert(t[i]-'a',i,0);T.build(0);int l,r;scanf("%d%d",&l,&r);S.query(l,r);printf("%lld\n",T.calc());T.clear();}return 0;
}

【NOI2018】你的名字【后缀自动机】【可持久化线段树合并】【乱搞】相关推荐

  1. [BJWC2018]Border 的四种求法(后缀自动机+链分治+线段树合并)

    题目描述 给一个小写字母字符串 S ,q 次询问每次给出 l,r ,求 s[l..r] 的 Border . Border: 对于给定的串 s ,最大的 i 使得 s[1..i] = s[|s|-i+ ...

  2. UOJ #395 BZOJ 5417 Luogu P4770 [NOI2018]你的名字 (后缀自动机、线段树合并)

    NOI2019考前做NOI2018题.. 题目链接: (bzoj) https://www.lydsy.com/JudgeOnline/problem.php?id=5417 (luogu) http ...

  3. 【CF700E】Cool Slogans【后缀自动机】【可持久化线段树合并】【树上倍增】

    传送门 题意:给定字符串SSS,求一堆字符串s1,s2,s3,...,sks_1,s_2,s_3,...,s_ks1​,s2​,s3​,...,sk​,满足s1s_1s1​是SSS的子串,且sis_i ...

  4. BZOJ 3483 SGU505 Prefixes and suffixes(字典树+可持久化线段树)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3483 [题目大意] 给出一些串,同时给出m对前缀后缀,询问有多少串满足给出的前缀后缀模 ...

  5. 【用学校抄作业带你走进可持久化线段树(主席树)】可持久化线段树概念+全套模板+例题入门:[福利]可持久化线段树)

    我似乎很少写这种算法博客 可持久化线段树概念 概念介绍(类比帮助理解) 简单分析一下时间和空间复杂度(内容池) 模板 结构体变量 建树模板 单点修改模板 单点查询模板 区间修改模板(pushup) 区 ...

  6. P4770:你的名字(SAM、线段树合并)

    文章目录 前言 解析 前言 1000A快乐!!!awa 没有想象中的那么恶心. 解析 先考虑每次都询问 [1,n][1,n][1,n] 如何做. 正难则反,用T所有本质不同串数量减去是S串子串又是T的 ...

  7. 【BZOJ4504】K个串 可持久化线段树+堆

    [BZOJ4504]K个串 Description 兔子们在玩k个串的游戏.首先,它们拿出了一个长度为n的数字序列,选出其中的一个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只被统计 ...

  8. SP10628 COT - Count on a tree (树剖+可持久化线段树)

    题意: 给定一个包含 N 个结点的树. 树节点从 1 到 N编号..每个节点有一个整数权值. 我们会要求您执行以下操作: u v k : 询问从节点 u 到 节点 v 的路径上的第k小的权值 输入 在 ...

  9. 解题报告:P3834 【模板】可持久化线段树 2(主席树)详解

    P3834 [模板]可持久化线段树 2(主席树) 题解 P3834 [[模板]可持久化线段树 2(主席树)] 1)静态求第k大数 可持久化线段树,不能用堆的方法存子结点了,所以用指针l表示左儿子r表示 ...

最新文章

  1. 【CV】吴恩达机器学习课程笔记第16章
  2. pdf复制乱码_一键解决PDF转换问题,这个网站好用到爆!
  3. 宝塔php的opcache模块未载入,宝塔面板CPU负载过高使用opcache扩展的解决方法
  4. 批量修改远程linux服务器密码
  5. C# 函数 传入 C++动态库中 做回调函数
  6. 前端学习(1110):this指向问题
  7. 关于计算机的英语演讲稿三分钟,以计算机为题的英语演讲稿5
  8. haproxy安装配置及haproxy+keepalived简单配置
  9. PostGIS创建Gis空间数据库,shp数据入库
  10. tensorflow出现问题Passing (type, 1) or 1type as a synonym of type is deprecated
  11. 红包算法 递归 php,【杂谈】PHP递归算法(二)
  12. unity屏幕分辨率设置注意及代码
  13. 「PKUSC2018」最大前缀和 LOJ#6433BZOJ5369
  14. hover效果移除时元素还原太生硬的情况
  15. “云适配”获1亿元B+轮融资,盯上了大企业的移动化需求
  16. 今日微语早报 每日精选12条新闻简报
  17. 看到大一的PS作业,忍不住想吐槽!!
  18. 输出菱形图案Python
  19. 浏览器交响曲 (一)浏览器中的js执行机制
  20. PT柜、进线柜、出线柜、隔离柜

热门文章

  1. 一张纸能有多大力量?
  2. 日本的电视节目到底能有多特别?
  3. 这6个地方不去简直太可惜!
  4. 现在竟然还有补丝袜的?
  5. 40张令人震惊的对比图,第一张细思恐极
  6. “凡尔赛文学”疯狂刷屏!数学家们也拼命“装”了起来,哈哈哈哈哈
  7. 21岁就破解困扰人们300年难题的天才,却一生坎坷,怀才不遇,至死还得不到认可...
  8. 干货|MIT线性代数课程精细笔记[第二课]
  9. python函数参数类型检查_Python中实现参数类型检查的简单方法
  10. php cbd架构,CBD模式