先考虑l=1,r=n,并且不要求本质不同的情况。对原串建SAM,将询问串在上面跑,得到每个前缀的最长匹配后缀即可得到答案。

  然后考虑本质不同。对询问串也建SAM,统计每个节点的贡献,得到该点right集合中任意一个的匹配长度即可。

  然后考虑原问题。我们需要求的仍然只是每个前缀的最长匹配后缀。通过线段树合并得到原串SAM每个点的right集合,同样将询问串在上面跑,跑的时候根据所达点right集合在给定区间中的最大值得到该点极限匹配长度,判断是否能在该点匹配(即极限匹配长度是否不小于该点所表示的最短长度),若不能则跳fail。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define N 1000010
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;
}
char s[N];
int Q,match[N],tmp[N],root[N],cnt;
struct data{int l,r,x;
}tree[N*40];
void ins(int &k,int l,int r,int x)
{
tree[++cnt]=tree[k],k=cnt;tree[k].x=max(tree[k].x,x);
if (l==r) return;
int mid=l+r>>1;
if (x<=mid) ins(tree[k].l,l,mid,x);
else ins(tree[k].r,mid+1,r,x);
}
int merge(int x,int y,int l,int r)
{
if (!x||!y) return x|y;
int k=++cnt;
tree[k].x=max(tree[x].x,tree[y].x);
if (l<r)
{
int mid=l+r>>1;
tree[k].l=merge(tree[x].l,tree[y].l,l,mid);
tree[k].r=merge(tree[x].r,tree[y].r,mid+1,r);
}
return k;
}
int query(int k,int l,int r,int x,int y)
{
if (!k) return 0;
if (l==x&&r==y) return tree[k].x;
int mid=l+r>>1;
if (y<=mid) return query(tree[k].l,l,mid,x,y);
else if (x>mid) return query(tree[k].r,mid+1,r,x,y);
else
{
int u=query(tree[k].r,mid+1,r,mid+1,y);
if (u) return u;else return query(tree[k].l,l,mid,x,mid);
}
}
struct SAM
{
int n,son[N][26],fail[N],len[N],id[N],q[N],f[N],cnt,last;
int newnode(){cnt++;memset(son[cnt],0,sizeof(son[cnt]));fail[cnt]=len[cnt]=0;return cnt;}
void extend(int c)
{
int x=newnode(),p=last;last=x;len[x]=len[p]+1;id[len[x]]=x;
while (!son[p][c]&&p) 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=newnode();
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];
}
}
}
void build(char *s)
{
cnt=0;last=1;newnode();n=strlen(s+1);
for (int i=1;i<=n;i++) extend(s[i]-'a');
for (int i=0;i<=n;i++) tmp[i]=0;
for (int i=1;i<=cnt;i++) tmp[len[i]]++;
for (int i=1;i<=n;i++) tmp[i]+=tmp[i-1];
for (int i=1;i<=cnt;i++) q[tmp[len[i]]--]=i;
}
void run(char *s,int l,int r)
{
int m=strlen(s+1);
int k=1,t=0;
for (int i=1;i<=m;i++)
{
int c=s[i]-'a';
while (!son[k][c]&&k) k=fail[k],t=len[k];
if (!k) k=1,t=0;
else k=son[k][c],t++;
while (k)
{
int u=query(root[k],1,n,l,r);
if (u-l+1<=len[fail[k]]) {k=fail[k],t=len[k];continue;}
t=min(t,u-l+1);break;
}
if (!k) k=1,t=0;
match[i]=t;
}
}
void getright()
{
for (int i=1;i<=n;i++) ins(root[id[i]],1,n,i);
for (int i=cnt;i>=1;i--)
{
int x=q[i];
root[fail[x]]=merge(root[fail[x]],root[x],1,n);
}
}
ll calc()
{
ll ans=0;
for (int i=1;i<=cnt;i++) f[i]=N;
for (int i=1;i<=n;i++) f[id[i]]=match[i];
for (int i=cnt;i>=1;i--)
{
int x=q[i];
ans+=max(0,len[x]-max(len[fail[x]],f[x]));
f[fail[x]]=min(f[fail[x]],f[x]);
}
return ans;
}
}S,T;
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
scanf("%s",s+1);S.build(s);S.getright();
Q=read();
while (Q--)
{
scanf("%s",s+1);
int l=read(),r=read();
S.run(s,l,r);
T.build(s);printf(LL,T.calc());
}
return 0;
}

  

Luogu4770 NOI2018你的名字(后缀自动机+线段树合并)的更多相关文章

  1. luogu4770 [NOI2018]你的名字 后缀自动机 + 线段树合并

    其实很水的一道题吧.... 题意是:每次给定一个串\(T\)以及\(l, r\),询问有多少个字符串\(s\)满足,\(s\)是\(T\)的子串,但不是\(S[l .. r]\)的子串 统计\(T\) ...

  2. bzoj5417/luoguP4770 [NOI2018]你的名字(后缀自动机+线段树合并)

    bzoj5417/luoguP4770 [NOI2018]你的名字(后缀自动机+线段树合并) bzoj Luogu 给出一个字符串 $ S $ 及 $ q $ 次询问,每次询问一个字符串 $ T $ ...

  3. BZOJ5417[Noi2018]你的名字——后缀自动机+线段树合并

    题目链接: [Noi2018]你的名字 题目大意:给出一个字符串$S$及$q$次询问,每次询问一个字符串$T$有多少本质不同的子串不是$S[l,r]$的子串($S[l,r]$表示$S$串的第$l$个字 ...

  4. BZOJ.5417.[NOI2018]你的名字(后缀自动机 线段树合并)

    LOJ 洛谷 BZOJ 考虑\(l=1,r=|S|\)的情况: 对\(S\)串建SAM,\(T\)在上面匹配,可以得到每个位置\(i\)的后缀的最长匹配长度\(mx[i]\). 因为要去重,对\(T\ ...

  5. NOI 2018 你的名字 (后缀自动机+线段树合并)

    题目大意:略 令$ION2017=S,ION2018=T$ 对$S$建$SAM$,每次都把$T$放进去跑,求出结尾是i的前缀串,能匹配上$S$的最长后缀长度为$f_{i}$ 由于$T$必须在$[l,r ...

  6. [NOI2018]你的名字(后缀自动机+线段树)

    题目描述 小A 被选为了ION2018 的出题人,他精心准备了一道质量十分高的题目,且已经把除了题目命名以外的工作都做好了. 由于ION 已经举办了很多届,所以在题目命名上也是有规定的,ION 命题手 ...

  7. BZOJ3413: 匹配(后缀自动机 线段树合并)

    题意 题目链接 Sol 神仙题Orz 后缀自动机 + 线段树合并... 首先可以转化一下模型(想不到qwq):问题可以转化为统计\(B\)中每个前缀在\(A\)中出现的次数.(画一画就出来了) 然后直 ...

  8. cf666E. Forensic Examination(广义后缀自动机 线段树合并)

    题意 题目链接 Sol 神仙题Orz 后缀自动机 + 线段树合并 首先对所有的\(t_i\)建个广义后缀自动机,这样可以得到所有子串信息. 考虑把询问离线,然后把\(S\)拿到自动机上跑,同时维护一下 ...

  9. [Luogu5161]WD与数列(后缀数组/后缀自动机+线段树合并)

    https://blog.csdn.net/WAautomaton/article/details/85057257 解法一:后缀数组 显然将原数组差分后答案就是所有不相交不相邻重复子串个数+n*(n ...

  10. 模板—字符串—后缀自动机(后缀自动机+线段树合并求right集合)

    模板—字符串—后缀自动机(后缀自动机+线段树合并求right集合) Code: #include <bits/stdc++.h> using namespace std; #define ...

随机推荐

  1. Java 面向对象(十)

    常用类之Arrays java.util.Arrays 类是 JDK 提供的一个工具类,用来处理数组的各种方法,而且每个方法基本上都是静态方法,能直接通过类名Arrays调用. 1.asList 返回 ...

  2. Python日志库logging总结-可能是目前为止将logging库总结的最好的一篇文章

    在部署项目时,不可能直接将所有的信息都输出到控制台中,我们可以将这些信息记录到日志文件中,这样不仅方便我们查看程序运行时的情况,也可以在项目出现故障时根据运行时产生的日志快速定位问题出现的位置. 1. ...

  3. Android插件化(4):OpenAtlasの插件的卸载与更新

    Android插件化(4):OpenAtlasの插件的卸载与更新   转 https://www.300168.com/yidong/show-2779.html 核心提示:如果看过我的前两篇博客An ...

  4. [webpack]手写一个mvp版本的webpack

    let fs = require('fs'); let path = require('path'); let babylon = require('babylon'); // Babylon 把源码 ...

  5. 20Flutter通过TabController定义顶部tab切换,介绍生命周期函数

    基本使用: import 'package:flutter/material.dart'; class TabBarControllerPage extends StatefulWidget { Ta ...

  6. 阶段5 3.微服务项目【学成在线】_day18 用户授权_13-细粒度授权-细粒度授权介绍

    3 细粒度授权 3.1 需求分析 什么是细粒度授权? 细粒度授权也叫数据范围授权,即不同的用户所拥有的操作权限相同,但是能够操作的数据范围是不一样的.一个 例子:用户A和用户B都是教学机构,他们都拥有 ...

  7. ios排序NSArray(数字.字符串)

    NSArray *originalArray = @[@"1",@"21",@"12",@"11",@"0&q ...

  8. 【设计】PC Web端框架组件

    https://uedart.com/demo/templatesWebKit/index.html#g=1&p=%E4%BD%9C%E5%93%81%E9%A6%96%E9%A1%B5 移动 ...

  9. AWS 存储服务(三)

    目录 AWS S3 业务场景 挑战 解决方案 S3的好处 S3 属性 存储桶 Buckets 对象 Object S3 特性 S3 操作 可用性和持久性 一致性 S3 定价策略 S3高级功能 存储级别 ...

  10. 做了一个非竞价排名、有较详细信息的程序员职位 match 网站

    作为一个程序员,每次看机会当我去 BOSS 直聘 或者拉勾网进行搜索时,返回的顺序并不是根据匹配程度,而是这些公司给 BOSS 直聘或者拉勾网付了多少钱.这种百度式的竞价排名机制并没有把我做为求职者的 ...