传送门

题意:给定字符串SSS,求一堆字符串s1,s2,s3,...,sks_1,s_2,s_3,...,s_ks1​,s2​,s3​,...,sk​,满足s1s_1s1​是SSS的子串,且sis_isi​在si−1s_{i-1}si−1​中至少出现两次,最大化kkk

∣S∣≤200000|S| \leq 200000∣S∣≤200000

神仙题

显然建出后缀自动机然后在failfailfail树上乱搞

但很快发现不好描述出现两次

于是考虑回归到后缀自动机的本质:endposendposendpos

对于子串S,TS,TS,T,如果SSS在TTT中出现两次

那么在某一个TTT的覆盖范围里,SSS出现了两次

换句话说,对于TTT的任意一个endposendposendpos,记为pos[T]pos[T]pos[T],其覆盖范围为[pos[T]−len[T],pos[T]][pos[T]-len[T],pos[T]][pos[T]−len[T],pos[T]]

这段里出现了两个[pos[S]−len[S],pos[S]][pos[S]-len[S],pos[S]][pos[S]−len[S],pos[S]]

即[pos[T]−len[T]+len[S],pos[T]][pos[T]-len[T]+len[S],pos[T]][pos[T]−len[T]+len[S],pos[T]]中有至少两个SSS的endposendposendpos

于是可以用可持久化线段树来维护,由于某个点的endposendposendpos等于其failfailfail树的儿子的endposendposendpos的并集,写个线段树合并即可。

查询的时候由于是单调的,用倍增查最下面的满足条件的祖先。

复杂度O(nlog2n)O(nlog^2n)O(nlog2n)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#define MAXN 400005
using namespace std;
namespace SGT
{int ch[MAXN<<5][2],sum[MAXN<<5],cnt;inline int copy(const int& x){int ans=++cnt;ch[ans][0]=ch[x][0],ch[ans][1]=ch[x][1],sum[ans]=sum[x];return ans;}void insert(int& x,int l,int r,int k){++sum[x=++cnt];if (l==r) return;int mid=(l+r)>>1;if (k<=mid) insert(ch[x][0],l,mid,k);else insert(ch[x][1],mid+1,r,k);}int merge(int x,int y){if (!x||!y) return x|y;int p=copy(x);sum[p]+=sum[y];ch[p][0]=merge(ch[p][0],ch[y][0]);ch[p][1]=merge(ch[p][1],ch[y][1]);return p;}int getpos(int x,int l,int r){if (l==r) return l;int mid=(l+r)>>1;if (sum[ch[x][0]]) return getpos(ch[x][0],l,mid);else return getpos(ch[x][1],mid+1,r);}int query(int x,int l,int r,int ql,int qr){if (ql<=l&&r<=qr) return sum[x];if (r<ql||qr<l) 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 n;
char s[MAXN];
namespace SAM
{int ch[MAXN][26],fa[MAXN],len[MAXN],pos[MAXN],tot=1,las=1;int rt[MAXN];void insert(int c){int cur=++tot,p=las;len[cur]=len[p]+1;las=cur;for (;p&&!ch[p][c];p=fa[p]) ch[p][c]=cur;if (!p) return (void)(fa[cur]=1);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;}}int jump[MAXN][20];int a[MAXN],c[MAXN],f[MAXN]={-1};inline bool check(int x,int y){return len[x]==0||SGT::query(rt[x],1,n,pos[y]-len[y]+len[x],pos[y])>=2;}int build(){for (int i=1;i<=n;i++) insert(s[i]-'a'),SGT::insert(rt[las],1,n,i);for (int i=1;i<=tot;i++) ++c[len[i]];for (int i=1;i<=n;i++) c[i]+=c[i-1];for (int i=tot;i>=1;i--) a[c[len[i]]--]=i;for (int i=tot;i>=1;i--){pos[a[i]]=SGT::getpos(rt[a[i]],1,n);rt[fa[a[i]]]=SGT::merge(rt[fa[a[i]]],rt[a[i]]);}for (int i=1;i<=tot;i++){jump[a[i]][0]=fa[a[i]];for (int k=1;k<20;k++) jump[a[i]][k]=jump[jump[a[i]][k-1]][k-1];int anc=a[i];for (int k=19;k>=0;k--) if (!check(jump[anc][k],a[i])) anc=jump[anc][k];anc=fa[anc];f[a[i]]=f[anc]+1;}int mx=0;for (int i=1;i<=tot;i++) mx=max(mx,f[i]);return mx;}
}
int main()
{scanf("%d",&n);scanf("%s",s+1);printf("%d\n",SAM::build());return 0;
}

【CF700E】Cool Slogans【后缀自动机】【可持久化线段树合并】【树上倍增】相关推荐

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

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

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

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

  3. 洛谷 - P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并(树上差分+线段树合并)

    题目链接:点击查看 题目大意:给出一棵树,再给出 m 次操作,每次操作会选择两个点 ( x , y ) ,使得这条路径上的所有点的种类 z 加一,最后问每个点的哪个种类出现的频率最高,若多个种类出现频 ...

  4. 雨中的尾巴(线段树合并+树上差分)

    哇这道题 恶心死我 首先要知道,树上差分一般解决的问题是关于树上的覆盖问题 然后遇到覆盖问题尽量不要打树剖(会慢很多) 关于此题 因为这道题覆盖的是 从xxx到yyy的点 所以我们在 x,yx,yx, ...

  5. Codeforces.700E.Cool Slogans(后缀自动机 线段树合并 DP)

    题目链接 \(Description\) 给定一个字符串\(s[1]\).一个字符串序列\(s[\ ]\)满足\(s[i]\)至少在\(s[i-1]\)中出现过两次(\(i\geq 2\)).求最大的 ...

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

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

  7. BZOJ 3277 串 BZOJ 3473 字符串 (广义后缀自动机、时间复杂度分析、启发式合并、线段树合并、主席树)...

    标签那么长是因为做法太多了... 题目链接: (bzoj 3277) https://www.lydsy.com/JudgeOnline/problem.php?id=3277 (bzoj 3473) ...

  8. 【CF666E】Forensic Examination - 广义后缀自动机+线段树合并

    广义SAM专题的最后一题了--呼 题意: 给出一个长度为$n$的串$S$和$m$个串$T_{1\cdots m}$,给出$q$个询问$l,r,pl,pr$,询问$S[pl\cdots pr]$在$T_ ...

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

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

最新文章

  1. 基于SSM实现公司内部培训系统的开发
  2. CPU缓存L1/L2/L3工作原理
  3. Maven nexus私服仓库类型说明及配置阿里云代理仓库
  4. Linux DNS服务配置与管理详解
  5. Bean的依赖注入的数据类型
  6. Robotframework集成jenkins执行用例
  7. 如何实现同一个页面里面两个页面的相互切换(window.onscroll)
  8. python提高——进程、线程、协程对比及代码实现
  9. 百度DuerOS与高通合推手机语音交互解决方案,谁会欢喜谁要愁?
  10. oracle 12c dbca 无法发现 asm diskgroup
  11. react redux 简化_Redux 源码解析
  12. 可以在python3下面用的pyh
  13. cntext:一款 Python文本分析包
  14. 在SPSS中使用广义估算方程对非独立相关数据进行分析的方法
  15. 用R语言下载任意地区DEM数据
  16. phpcms v9 邓士鹏(石家庄职业技术学院)
  17. (附源码)springboot家庭财务分析系统 毕业设计641323
  18. 关于算法的学习以及一些总结(一)
  19. android友盟微信分享到朋友圈,干货,Umeng分享纯图片(避免跳坑)到_微信,朋友圈等...
  20. 网易邮箱出现 FA_INVALID_SESSION

热门文章

  1. 土木工程到底有多惨?哭了哭了......
  2. 2018 Kaggle 报告:在技术领域,女性从业者持续减少,00后开始展露头脚
  3. 你试过不用if撸代码吗?
  4. Lanchester战争模型:用可分离变量的微分方程占卜战事
  5. 今天,送你一份交通行业最全数据集(共享单车、自动驾驶、网约出租车、交通信号识别)
  6. python功能选择模块_python – 组合功能和功能模块
  7. python with循环_Python for循环、while循环
  8. 与ln的指数转化公式_高考数学48条秒杀型公式与方法
  9. 工作原理是什么_磁翻板液位计工作原理是什么?
  10. 单片机矩阵消抖延时c语言,单片机矩阵按键定时器消抖程序源码