CF700E:Cool Slogans(后缀自动机,线段树合并)
Posted refun
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF700E:Cool Slogans(后缀自动机,线段树合并)相关的知识,希望对你有一定的参考价值。
Description
给你一个字符串,如果一个串包含两个不重叠的相同子串,那么这个串的价值就是子串的价值+1。问你给定字符串的最大价值子串的价值。
Input
第一行读入字符串长度$n$,第二行是字符串。
Output
一行答案。
Sample Input1
3
abc
Sample Output1
1
Sample Input2
5
ddddd
Sample Output2
5
Sample Input3
11
abracadabra
Sample Output3
3
Solution
首先把后缀树建立出来,然后从下往上线段树合并一下$endpos$。
设$f[i]$表示从后缀树的根$DP$到了$i$节点的最大价值,$top[i]$表示$i$节点是从哪个节点转移来的。
如果父亲代表的字符串在当前节点代表的字符串中出现了两次及以上,那么就$f[x]=f[fa]+1,top[x]=x$
否则$f[x]=f[fa],top[x]=top[fa]$
父亲代表的字符串在当前节点代表的字符串中出现的次数可以直接根据$SAM$的$step$数组和线段树合并出的$endpos$什么的直接判断一下。
Code
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #define N (800009) 5 using namespace std; 6 7 struct Sgt{int ls,rs,val;}Segt[N<<5]; 8 struct Edge{int to,next;}edge[N<<1]; 9 int n,ans,sgt_num,Root[N],f[N],top[N]; 10 int head[N],num_edge; 11 int last=1,p,q,np,nq,cnt=1; 12 int fa[N],son[N][26],step[N],pos[N]; 13 char s[N]; 14 15 void add(int u,int v) 16 { 17 edge[++num_edge].to=v; 18 edge[num_edge].next=head[u]; 19 head[u]=num_edge; 20 } 21 22 void Insert(int x,int r) 23 { 24 p=last; np=last=++cnt; 25 step[np]=step[p]+1; pos[np]=r; 26 while (p && !son[p][x]) son[p][x]=np, p=fa[p]; 27 if (!p) fa[np]=1; 28 else 29 { 30 q=son[p][x]; 31 if (step[q]==step[p]+1) fa[np]=q; 32 else 33 { 34 nq=++cnt; step[nq]=step[p]+1; pos[nq]=r; 35 memcpy(son[nq],son[q],sizeof(son[q])); 36 fa[nq]=fa[q]; fa[q]=fa[np]=nq; 37 while (son[p][x]==q) son[p][x]=nq, p=fa[p]; 38 } 39 } 40 } 41 42 void Update(int &now,int l,int r,int x) 43 { 44 if (!now) now=++sgt_num; 45 Segt[now].val++; 46 if (l==r) return; 47 int mid=(l+r)>>1; 48 if (x<=mid) Update(Segt[now].ls,l,mid,x); 49 else Update(Segt[now].rs,mid+1,r,x); 50 } 51 52 int Merge(int x,int y) 53 { 54 if (!x || !y) return x|y; 55 int now=++sgt_num; 56 Segt[now].ls=Merge(Segt[x].ls,Segt[y].ls); 57 Segt[now].rs=Merge(Segt[x].rs,Segt[y].rs); 58 Segt[now].val=Segt[x].val+Segt[y].val; 59 return now; 60 } 61 62 int Query(int now,int l,int r,int l1,int r1) 63 { 64 if (!now) return 0; 65 if (l>r1 || r<l1) return 0; 66 if (l1<=l && r<=r1) return Segt[now].val; 67 int mid=(l+r)>>1; 68 return Query(Segt[now].ls,l,mid,l1,r1)+Query(Segt[now].rs,mid+1,r,l1,r1); 69 } 70 71 void DFS(int x) 72 { 73 if (pos[x]) Update(Root[x],1,n,pos[x]); 74 for (int i=head[x]; i; i=edge[i].next) 75 { 76 DFS(edge[i].to); 77 Root[x]=Merge(Root[x],Root[edge[i].to]); 78 } 79 } 80 81 void DP(int x) 82 { 83 for (int i=head[x]; i; i=edge[i].next) 84 { 85 int y=edge[i].to; 86 if (x==1) f[y]=1, top[y]=y; 87 else if (Query(Root[top[x]],1,n,pos[y]-step[y]+step[top[x]],pos[y]-1)) 88 f[y]=f[x]+1, top[y]=y; 89 else f[y]=f[x], top[y]=top[x]; 90 DP(edge[i].to); 91 ans=max(ans,f[edge[i].to]); 92 } 93 } 94 95 int main() 96 { 97 scanf("%d%s",&n,s); 98 for (int i=0; i<n; ++i) Insert(s[i]-‘a‘,i+1); 99 for (int i=2; i<=cnt; ++i) add(fa[i],i); 100 DFS(1); DP(1); 101 printf("%d ",ans); 102 }
以上是关于CF700E:Cool Slogans(后缀自动机,线段树合并)的主要内容,如果未能解决你的问题,请参考以下文章