hdu 5008 Boring String Problem(后缀自动机构造后缀树)
来源:互联网 发布:米饭的危害 知乎 编辑:程序博客网 时间:2024/04/26 14:24
hdu 5008 Boring String Problem(后缀自动机构造后缀树)
题意:给出一个字符串s,然后每次询问一个k,求s的所有子串中,字典序第k小的是谁?多个解,则输出最左边的那个
解题思路:这道题应该是为后缀树量身定制的吧。只要构造出了后缀树,然后按字典序遍历就可以得出每个节点包含的子串的字典序的范围了,而且必然是个连续的区间范围。但是我不会后缀树啊。。比赛的时候突然想到,后缀自动机是可以构造后缀树的,虽然以前没写过,但还是硬着头皮上吧,居然还真的让我给撸出来了。我的做法是这样的,将s翻转后建立sam,因为sam的parent tree就是逆序的后缀树嘛。构建好parent tree后,遍历每个节点,对于节点u,它的字节点集合{v1,v2...vn}之间的关系是,这些节点包含的子串的长为val[u]的后缀都是一样的(当我们翻转s建立sam后,后缀就变前缀了),也就是u的代表串,而它们的长为val[u]+1的后缀必然又都是不一样的。我们把{v1,v2..vn}按不一样的那个字符的字典序排序,就得到了后缀树了。那么每个节点的代表串最先出现的位置怎么确定的呢?在逆序构造的后缀自动机中,最现出现的前缀,即为最后出现的后缀。我们要在后缀自动机中确定最后出现的位置,只要将每个前缀出现的位置更新到相应的节点,然后往上更新即可。
代码:
#include<stdio.h>#include<string.h>#include<algorithm>#include<vector>#define ll __int64using namespace std ;const int maxn = 211111 ;vector<int> vec[maxn<<1] ;char s[maxn] ;int len ;int fa[maxn<<1] , val[maxn<<1] , c[26][maxn<<1] ;int tot , last , p[maxn<<1] ;int wv[maxn] , ws[maxn] , pos[maxn<<1] ;ll T , gg[maxn<<1] ;inline int new_node ( int _val ) { val[++tot] = _val ; for ( int i = 0 ; i < 26 ; i ++ ) c[i][tot] = 0 ; fa[tot] = p[tot] = 0 ; vec[tot].clear () ; return tot ;}void add ( int k ) { int p = last , i ; int np = new_node ( val[p] + 1 ) ; while ( p && !c[k][p] ) c[k][p] = np , p = fa[p] ; if ( !p ) fa[np] = 1 ; else { int q = c[k][p] ; if ( val[q] == val[p] + 1 ) fa[np] = q ; else { int nq = new_node ( val[p] + 1 ) ; for ( i = 0 ; i < 26 ; i ++ ) c[i][nq] = c[i][q] ; fa[nq] = fa[q] ; fa[q] = fa[np] = nq ; while ( p && c[k][p] == q ) c[k][p] = nq , p = fa[p] ; } } last = np ;}void init () { T = tot = 0 ; last = new_node ( 0 ) ;}void SORT () { for ( int i = 0 ; i < maxn ; i ++ ) wv[i] = 0 ; for ( int i = 1 ; i <= tot ; i ++ ) wv[val[i]] ++ ; for ( int i = 1 ; i < maxn ; i ++ ) wv[i] += wv[i-1] ; for ( int i = 1 ; i <= tot ; i ++ ) ws[wv[val[i]]--] = i ;}int cmp ( int i , int j ) { int w = fa[i] ; int l = val[w] ; i = s[p[i]-l] ; j = s[p[j]-l] ; return i < j ;}void dfs ( int u ) { T += val[u] - val[fa[u]] ; gg[u] = T ; int k = vec[u].size () ; for ( int i = 0 ; i < k ; i ++ ) dfs ( vec[u][i] ) ;}int cmp1 ( int i , int j ) { return gg[i] < gg[j] ;}void solve () { SORT () ; for ( int i = 2 ; i <= tot ; i ++ ) vec[fa[i]].push_back ( i ) ; int now = 1 ; for ( int i = 0 ; i < len ; i ++ ) { int k = s[i] - 'a' ; now = c[k][now] ; p[now] = i ; } for ( int i = tot ; i >= 1 ; i -- ) { int v = ws[i] ; p[fa[v]] = max ( p[v] , p[fa[v]] ) ; pos[i] = i ; } for ( int i = 1 ; i <= tot ; i ++ ) sort ( vec[i].begin() , vec[i].end () , cmp ) ; dfs ( 1 ) ; /* for ( int i = 1 ; i <= tot ; i ++ ) printf ( "%d " , gg[i] ) ; puts( "" ) ;*/ sort ( pos + 1 , pos + tot + 1 , cmp1 ) ;}void query ( ll& l , ll& r , ll v ) { ll k = ( l ^ r ^ v ) + 1 ; if ( k > T ) { l = 0 , r = 0 ; } else { int L = 1 , R = tot ; while ( L <= R ) { int m = ( L + R ) >> 1 ; if ( gg[pos[m]] >= k ) R = m - 1 ; else L = m + 1 ; } R = L ; int ans = pos[R] ; k -= gg[pos[R-1]] ; l = len - p[ans] ; r = l + val[fa[ans]] + k - 1 ; } printf ( "%I64d %I64d\n" , l , r ) ;}int main () { while ( scanf ( "%s" , s ) != EOF ) { ll l = 0 , r = 0 ; len = strlen ( s ) ; reverse ( s , s + len ) ; init () ; for ( int i = 0 ; i < len ; i ++ ) add ( s[i] - 'a' ) ; solve () ; int q ; scanf ( "%d" , &q ) ; while ( q -- ) { ll v ; scanf ( "%I64d" , &v ) ; query ( l , r , v ) ; } }}
2 0
- hdu 5008 Boring String Problem(后缀自动机构造后缀树)
- hdu 5008 Boring String Problem(后缀数组)
- HDU 5008 Boring String Problem 后缀数组
- hdu 5008 Boring String Problem(后缀数组)
- hdu 5008 Boring String Problem 【后缀数组】
- hdu 5008 Boring String Problem 后缀数组
- HDU 5008 Boring String Problem 后缀数组
- HDU 5008 Boring String Problem 后缀数组 RMQ
- [后缀数组+二分+rmq] hdu 5008 Boring String Problem
- HDU - 5008 Boring String Problem (后缀数组+二分+RMQ)
- HDU 5008 Boring String Problem 二分 + 后缀数组
- 【后缀数组】 HDOJ 5008 Boring String Problem
- HDU 3518 Boring counting 后缀自动机
- hdu 5008(2014 ACM/ICPC Asia Regional Xi'an Online ) Boring String Problem(后缀数组&二分)
- hdu5008 Boring String Problem 后缀数组+二分
- hdu5008-Boring String Problem(后缀数组专题)
- hdu5008 Boring String Problem(后缀数组)
- 后缀数组 - hdu5008 Boring String Problem
- mysql 事务控制
- 四.FocusOverlayManager对焦管理
- stack操作
- 当前Java软件开发中几种认识误区
- uifont font 字体大全
- hdu 5008 Boring String Problem(后缀自动机构造后缀树)
- 2014.4新版uboot启动流程分析(建议看链接原文)
- ExpandableListView与Button结合使用
- C++学习笔记(第四章 函数的应用及多文件组织 之三)
- 什么是GCC?
- shell常见符号
- 用openssl命令生成证书
- 【内核研究】客户端中的线程
- Robotium重签名APK