题目链接

题意简述

给定一个串 \(S\)
多组询问 , 每次给定一个串 \(T\) 和一个 区间 \([l,r]\)
求串\(T\) 有多少个本质不同的子串 满足不是 \(S[l...r]\) 的子串

Sol

首先显然要么 \(SAM\) 要么 \(SA\)。
这种带区间还要求本质不同的的一般用 \(SAM\) 好做些吧。

先考虑每次询问的区间就是整个串我们怎么做。
考虑先补集转换,即先求出不合法的子串,然后用总的本质不同子串数减去这个值得到答案。

那么对 \(S\) 和 \(T\) 分别建立 \(SAM\)
之后我们直接拿着 \(T\) 在 \(S\) 上面跑, 对于每一个点记录它最长能够匹配上的长度,这样对于一个点来说,我们知道它表示的串的区间长度,并且由于后缀自动机的性质每一个串只会被一个节点表示,那么假设这个串能识别的串长为 \([l,r]\) ,它最长能够匹配的长度是 \(L\) 的话 ,贡献就是 \(max(0,L-l)\)

如何求出最长匹配长度?
当我们失配的时候同时让 \(T\) 上的点也往上跳直到符合匹配长度,那么这个时候这个点以及它的祖先都可以用这个匹配长度更新。
我们先把值打在一个点上,最后每个点子树内取个 \(max\) 就行了。

然后考虑询问的是区间怎么办。
我们只需要知道当前转移合不合法就行了,直接线段树合并出 endpos 集合,然后在 \(S\) 的 \(SAM\) 上走的时候判一下是否能够有一个串在询问区间内就行了。

有一个坑点是当我们的串区间超过的时候不能直接跳到父亲,因为可能你要求匹配的长度太长了,所以应该一点点把长度减小,当到了父亲的长度的时候再跳上去。

#include<bits/stdc++.h>
using namespace std;
#define Set(a,b) memset(a,b,sizeof(a))
#define Copy(a,b) memcpy(a,b,sizeof(a))
template<class T>inline void init(T&x){x=0;char ch=getchar();bool t=0;for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') t=1;for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch-48);if(t) x=-x;return;
}typedef long long ll;
const int N=5e5+10;
const int MAXN=N<<2;
const int MAXM=MAXN*30;
char S[N],T[N];int ans[MAXN];
int rt[MAXN];int ls[MAXM],rs[MAXM],size[MAXM];
bool tp;int cnt=0;
#define MID (l+r)>>1
inline void Insert(int&u,int l,int r,int p){u=++cnt;size[u]=1;if(l==r) return;int mid=MID;if(mid>=p) Insert(ls[u],l,mid,p);else Insert(rs[u],mid+1,r,p);
}
inline int Merge(int u,int v,int l,int r){if(!u||!v) return u|v;int p=++cnt;size[p]=size[u]+size[v];if(l==r) return p;int mid=MID;ls[p]=Merge(ls[u],ls[v],l,mid);rs[p]=Merge(rs[u],rs[v],mid+1,r);return p;
}
inline int Find(int u,int l,int r,int L,int R){if(!u||L>R||!size[u]) return 0;if(l==r) return l;int mid=MID;if(l>=L&&r<=R) {if(size[rs[u]]) return Find(rs[u],mid+1,r,L,R);return Find(ls[u],l,mid,L,R);}if(mid>=R) return Find(ls[u],l,mid,L,R);if(mid< L) return Find(rs[u],mid+1,r,L,R);int pos=0;if(size[rs[u]]) pos=Find(rs[u],mid+1,r,mid+1,R);if(!pos) pos=Find(ls[u],l,mid,L,mid);return pos;
}
struct SAM{int son[MAXN][26],fa[MAXN],len[MAXN];int n;int cnt=0,lst,id[MAXN],ws[MAXN];ll difnum=0;inline void Clear(){while(~cnt) {Set(son[cnt],0),fa[cnt]=len[cnt]=ws[cnt]=id[cnt]=0,ans[cnt]=0,--cnt;}lst=cnt=0;fa[0]=-1;}inline void extend(int c){int u=lst;int p=lst=++cnt;len[p]=len[u]+1;if(tp==1) Insert(rt[p],1,n,len[p]);while(~u&&!son[u][c]) son[u][c]=p,u=fa[u];if(~u) {int v=son[u][c];if(len[v]==len[u]+1) {fa[p]=v;return;}int q=++cnt;Copy(son[q],son[v]);fa[q]=fa[v];len[q]=len[u]+1;fa[v]=fa[p]=q;while(~u&&son[u][c]==v) son[u][c]=q,u=fa[u];}return;}inline void build(char*S,int l){Clear();fa[0]=-1;n=l;for(int i=1;i<=l;++i) extend(S[i]-'a');return;}inline void Prework(){difnum=0;for(int i=1;i<=cnt;++i) difnum+=len[i]-len[fa[i]];for(int i=1;i<=cnt;++i) ++ws[len[i]];for(int i=1;i<=n;++i) ws[i]+=ws[i-1];for(int i=cnt;i;--i) id[ws[len[i]]--]=i;return;}inline ll Calc(){ll Ans=difnum;for(int i=cnt;i;--i) {int u=id[i];ans[fa[u]]=max(ans[fa[u]],ans[u]);ans[u]=min(ans[u],len[u]);if(ans[u]>len[fa[u]]) Ans-=ans[u]-len[fa[u]];}return Ans;}inline void Tree_Build(){for(int i=cnt;i;--i) {int u=id[i];rt[fa[u]]=Merge(rt[fa[u]],rt[u],1,n);}}
}samS,samT;
int lS;
inline bool check(int u,int l,int r,int len){int R=Find(rt[u],1,lS,l,r);if(R-len+1<l) return 0;return 1;}
int main()
{scanf("%s",S+1);tp=1;samS.build(S,strlen(S+1));samS.Prework();samS.Tree_Build();tp=0;lS=strlen(S+1);int Q;init(Q);for(int i=1;i<=Q;++i){scanf("%s",T+1);int l,r;init(l),init(r);int len=strlen(T+1);samT.build(T,len);samT.Prework();int u=0,v=0,nowL=0;for(int j=1;j<=len;++j) {int c=T[j]-'a';while(~u&&(!samS.son[u][c]||!check(samS.son[u][c],l,r,nowL+1))) if(--nowL<=samS.len[samS.fa[u]]) u=samS.fa[u];//... 要一点一点减 , 减到了才跳 , 不然会判挂 !!if(nowL<0) nowL=0;if(~u&&samS.son[u][c]) {u=samS.son[u][c],v=samT.son[v][c];++nowL;}else u=0,nowL=0,v=0;while(v&&samT.len[samT.fa[v]]>=nowL) v=samT.fa[v];if(v) ans[v]=max(ans[v],nowL);}ll Ans=samT.Calc();printf("%lld\n",Ans);}return 0;
}

转载于:https://www.cnblogs.com/NeosKnight/p/10650788.html

【LuoguP4770】[NOI2018] 你的名字相关推荐

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

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

  2. [NOI2018]你的名字

    SAM写的太不熟练了~~SAM上的线段树合并也不熟练~~~ 调了半天样例 题目大意: 给定一个S,Q次询问,每次给出T,l,r, 求对于S[l,r],属于T的子串却不属于S[l,r]的子串有多少个 看 ...

  3. NOI2010~NOI2018选做

    [NOI2010] [NOI2010]海拔 高度只需要0/1,所以一个合法方案就是一个割,平面图求最小割. [NOI2010]航空管制 反序拓扑排序,每次取出第一类限制最大的放置,这样做答案不会更劣. ...

  4. 一个用SAM维护多个串的根号特技

    一个用SAM维护多个串的根号特技 基本介绍 在多个串的字符串题中,往往会出现一类题需要用到某个子串是否在一些母串中出现.此时对于 \(\text{parent}\) 树的 \(\text{right} ...

  5. oracle退出本循环,Oracle,跳出游标循环

    1,跳出游标的循环,不执行遍历了. 方法一:goto for c_row in 游标 loop if 条件 then dbms_output.put_line('测试跳出循环'); goto brea ...

  6. 【NOI2018】你的名字【后缀自动机】【可持久化线段树合并】【乱搞】

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

  7. 适合计算机应用的班群名称,班级同学群名字大全

    很多人现在都是一个班级建一个群,以便大家沟通交流,有什么事大家群里一说很方便,没事还可以吹吹牛B策策谈,那么同学班级群用什么样的名字好呢,在此起名网为大家收集整理了班级同学群名字大全.来看看吧. 最新 ...

  8. 2020卫星参数表大全_王者荣耀比较秀的名字 2020年比较骚气比较浪的王者荣耀名字大全...

    游戏中该起什么样的名字,才能让其他玩家很快的记住,从而达到认识更多玩家,认识到更多的朋友,达到交友目的. 2020年比较骚气比较浪的王者荣耀男性玩家名字大全如下: 骚里骚气 闷里闷气 孤独患者 洁癖患 ...

  9. C++:名字空间的使用

    首先明确一下要使用名字空间的目的是为了防止名字冲突. 一.访问名字空间中元素的3种方式: 1.可以自己去定义一些名字空间: namespace NameSpace1 {void fun(){}//该f ...

  10. spring 数组中随机取几个_别给孩子取这三种名字!截止年末,名字中的这几个字已经烂大街了...

    随着时代的进步,科技的发展,人们的生活水平不断,提高,许多的家庭都在拥有了不错的生活条件之后选择培养自己的下一代,随着宝宝的到来让整个家庭变得更加幸福,然而,许多家长却在给宝宝起名字这件事上放了愁,对 ...

最新文章

  1. Datawhale组队学习 Task04:队列(2天)
  2. R语言绘制三维散点图
  3. 批处理详细教程(三)
  4. php nodejs 前台,NodeJS之前端注册页面
  5. [转]SQL语句大全
  6. Spring(一)——总体介绍
  7. Android --- Retrofit 上传/下载文件扩展实现进度的监听
  8. python的datetime举例_Python datetime模块的使用示例
  9. 云计算openstack介绍
  10. 科大讯飞回应同传造假:人机耦合才是未来发展之道
  11. 拿工资,要做差不多的事
  12. Vue项目中使用eslint的笔录,编辑器采用sublime3
  13. mac 安装ps2017和破解教程
  14. vue 设置div圆角,只设置上面两个圆角,下面两个还是正方形
  15. Photoshop CS6下载包下载 及破解安装教程
  16. excel快速选择多行数据
  17. python实现isprime函数_Python实现isPrime函数
  18. Html监听Fbx文件加载,一些three.js的基础——加载FBX模型
  19. 从0到1构建计算机(4/12)--时序逻辑芯片:时序门、寄存器、RAM、计数器
  20. 大尺寸图片的性能和内存优化

热门文章

  1. amd显卡用黑苹果输出黑屏_黑苹果XFX讯景显卡刷vBIOS教程,使其黑苹果显卡更稳定完美,不再黑屏...
  2. 高分1、2号卫星原始遥感影像数据
  3. 应用软件提示服务器正在运行,服务器正在运行中怎么解决?IE浏览器服务器正在运行中的解决方法...
  4. el-select 下拉框样式修改
  5. error Code:410 Error Message:appid and openid not match 威富通技术支持,兴业银行微信支付接入支持
  6. Android百度地图修改定位时间间隔
  7. 计算机软件包含多选题,2008年职称计算机多选习题第二章信息产业和计算机软件...
  8. Latex 求职简历模版
  9. Installation for COMSOl(安装COMSOL)
  10. mac 设置maven环境变量并永久生效