zoukankan      html  css  js  c++  java
  • BZOJ3145 [Feyat cup 1.5]Str 后缀树、启发式合并

    传送门——BZOJCH


    考虑两种情况:

    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<bits/stdc++.h>
    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;
    }
    
  • 相关阅读:
    LeetCode 461. Hamming Distance
    LeetCode 442. Find All Duplicates in an Array
    LeetCode 448. Find All Numbers Disappeared in an Array
    LeetCode Find the Difference
    LeetCode 415. Add Strings
    LeetCode 445. Add Two Numbers II
    LeetCode 438. Find All Anagrams in a String
    LeetCode 463. Island Perimeter
    LeetCode 362. Design Hit Counter
    LeetCode 359. Logger Rate Limiter
  • 原文地址:https://www.cnblogs.com/Itst/p/11523818.html
Copyright © 2011-2022 走看看