博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
BZOJ3145 [Feyat cup 1.5]Str 后缀树、启发式合并
阅读量:4656 次
发布时间:2019-06-09

本文共 3825 字,大约阅读时间需要 12 分钟。


考虑两种情况:

1、答案由一个最长公共子串+可能的一个模糊匹配位置组成。这个用SAM求一下最长公共子串,但是需要注意只出现在\(S\)的开头和\(T\)的结尾的子串是不能够通过额外的一个模糊匹配得到更长的子串的,而对于其他的子串来说都可以。

2、答案由模糊位置两遍的子串构成。暴力就是枚举\(S\)\(T\)中模糊匹配的位置\(i,j\),那么长度就是\(LCS(i-1,j-1)+LCP(i+1,j+1)+1\)

注意到\(LCS(i,j)\)是对正串建SAM得到的前缀树上\(S[:i]\)\(T[:j]\)对应的点的LCA的Longest;\(LCP(i,j)\)是对反串建SAM得到的后缀树上的\(S[i:]\)\(T[j:]\)对应节点的LCA的Longest,所以我们可以把这个问题变为类似于两棵树上LCA深度和最大值的一个问题。

对于这个问题,我们考虑在前缀树上dfs,对于每个节点用set维护其子树内所有的合法前缀在后缀树上的dfs序,每一次加入一个子树的时候用启发式合并,用dfs序相邻的两个点的LCA更新当前点的答案,最后用当前点的Longest加上当前点的答案更新总答案。

#include
using namespace std;const int _ = 4e5 + 7;struct SAM{ int trs[_][27] , Lst[_] , fa[_] , pos[_] , cnt = 1; bool flg[_]; int extend(int p , int l , int c , bool f = 1){ int t = ++cnt; Lst[t] = pos[t] = l; flg[t] = f; while(p && !trs[p][c]){trs[p][c] = t; p = fa[p];} if(!p){fa[t] = 1; return t;} int q = trs[p][c]; if(Lst[q] == Lst[p] + 1){fa[t] = q; return t;} int k = ++cnt; memcpy(trs[k] , trs[q] , sizeof(trs[q])); fa[k] = fa[q]; fa[q] = fa[t] = k; Lst[k] = Lst[p] + 1; while(trs[p][c] == q){trs[p][c] = k; p = fa[p];} return t; } vector < int > ch[_]; int dfn[_] , to[_][20] , ts , dep[_]; void dfs(int x){ dfn[x] = ++ts; dep[x] = dep[fa[x]] + 1; to[x][0] = fa[x]; for(int i = 1 ; to[x][i - 1] ; ++i) to[x][i] = to[to[x][i - 1]][i - 1]; for(auto t : ch[x]){dfs(t); flg[x] |= flg[t];} } void build(){for(int i = 2 ; i <= cnt ; ++i) ch[fa[i]].push_back(i); dfs(dep[1] = 1);} int LCA(int p , int q){ if(dep[p] < dep[q]) swap(p , q); for(int i = 18 ; i >= 0 ; --i) if(dep[p] - (1 << i) >= dep[q]) p = to[p][i]; if(p == q) return Lst[p]; for(int i = 18 ; i >= 0 ; --i) if(to[p][i] != to[q][i]){p = to[p][i]; q = to[q][i];} return Lst[to[p][0]]; }}sam[3]; char str[_]; int id[2][_] , mx[_] , LS , LT , L , ans;struct cmp{bool operator ()(int a , int b){return sam[1].dfn[a] < sam[1].dfn[b];}};set < int , cmp > n1[_] , n2[_];void merge(int p , int q){ if(n1[p].size() + n2[p].size() < n1[q].size() + n2[q].size()){n1[p].swap(n1[q]); n2[p].swap(n2[q]);} for(auto t : n1[q]){ auto it = n2[p].lower_bound(t); if(it != n2[p].end()) mx[p] = max(mx[p] , sam[1].LCA(*it , t)); if(it != n2[p].begin()) mx[p] = max(mx[p] , sam[1].LCA(*--it , t)); } for(auto t : n2[q]){ auto it = n1[p].lower_bound(t); if(it != n1[p].end()) mx[p] = max(mx[p] , sam[1].LCA(*it , t)); if(it != n1[p].begin()) mx[p] = max(mx[p] , sam[1].LCA(*--it , t)); } for(auto t : n1[q]) n1[p].insert(t); for(auto t : n2[q]) n2[p].insert(t);}void dfs(int x){ if(sam[0].pos[x] && sam[0].pos[x] <= LS - 2) n1[x].insert(id[1][sam[0].pos[x] + 2]); if(sam[0].pos[x] >= LS + 2 && sam[0].pos[x] <= L - 2) n2[x].insert(id[1][sam[0].pos[x] + 2]); for(auto t : sam[0].ch[x]){dfs(t); merge(x , t);} if(mx[x]) ans = max(ans , mx[x] + sam[0].Lst[x] + 1);}int main(){ scanf("%s" , str + 1); LS = strlen(str + 1); str[LS + 1] = 'z' + 1; scanf("%s" , str + LS + 2); LT = strlen(str + LS + 2); L = strlen(str + 1); id[0][0] = id[1][L + 1] = 1; for(int i = 1 ; i <= L ; ++i) id[0][i] = sam[0].extend(id[0][i - 1] , i , str[i] - 'a'); for(int i = L ; i ; --i) id[1][i] = sam[1].extend(id[1][i + 1] , L - i + 1 , str[i] - 'a'); int pre = 1; for(int i = 1 ; i <= LS ; ++i) pre = sam[2].extend(pre , i , str[i] - 'a' , i != LS); int cur = 1 , len = 0; sam[2].build(); for(int i = LS + 2 ; i <= L ; ++i){ while(cur && !sam[2].trs[cur][str[i] - 'a']) len = sam[2].Lst[cur = sam[2].fa[cur]]; if(!cur) cur = 1; else{cur = sam[2].trs[cur][str[i] - 'a']; ++len;} ans = max(ans , len + !sam[2].flg[cur]); } sam[0].build(); sam[1].build(); dfs(1); cout << min(ans , min(LS , LT)); return 0;}

转载于:https://www.cnblogs.com/Itst/p/11523818.html

你可能感兴趣的文章
第一阶段冲刺3
查看>>
父类引用指向子类对象
查看>>
网页如何实现下载功能
查看>>
IT男专用表白程序
查看>>
读《大道至简》第六章感想
查看>>
ef linq 中判断实体中是否包含某集合
查看>>
章三 链表
查看>>
Solution for Concurrent number of AOS' for this application exceeds the licensed number
查看>>
CSE 3100 Systems Programming
查看>>
IntelliJ IDEA 的Project structure说明
查看>>
Java Security(JCE基本概念)
查看>>
Linux Supervisor的安装与使用入门
查看>>
创建 PSO
查看>>
JasperReport报表设计4
查看>>
项目活动定义 概述
查看>>
团队冲刺04
查看>>
我的Python分析成长之路8
查看>>
泛型在三层中的应用
查看>>
SharePoint2010 -- 管理配置文件同步
查看>>
.Net MVC3中取得当前区域的名字(Area name)
查看>>