2019 ccpc 网络赛 K-th occurrence(排名lcp模板)

题意:查询子串在原串中第k次出现的位置

思路: ST表 + 主席树 + 后缀数组

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef int lint;
const lint maxn = 100000 + 10;
const lint log_maxn = 20;
typedef int lint;

struct PST_BASE {
    //0 is invalid
    const static int MAX_NODE = maxn * log_maxn, MAXN = maxn;
    int n, tot, roots[MAXN], lson[MAX_NODE], rson[MAX_NODE], data[MAX_NODE];

    //Assume that maxv and n are given
    void Init(int _n) {
        //The content at the index 0 is never modified. So they are always 0
        n = _n;
        tot = 0;
        memset(roots, 0, (n + 1) * sizeof(roots[0]));
    }

    void Init(int a[], int _n, int maxv) {
        Init(_n);
        for (int i = 1; i <= n; ++i)
            Insert(roots[i-1], roots[i], 1, maxv, a[i], 1);
    }

    void Insert(int from, int &rt, int l, int r, int x, int num) {
        if (!rt) {
            rt = ++tot;
            lson[rt] = rson[rt] = data[rt] = 0;
        }
        data[rt] = data[from] + num;
        if (l < r) {
            int mid = (l + r) >> 1;
            if (x <= mid) {
                Insert(lson[from], lson[rt], l, mid, x, num);
                rson[rt] = rson[from];
            } else {
                lson[rt] = lson[from];
                Insert(rson[from], rson[rt], mid+1, r, x, num);
            }
        }
    }
    int Query(int L_rt, int R_rt, int l, int r, int k) {
        if (l == r)
            return l;
        int mid = (l+r) >> 1;
        int data_lc = data[lson[R_rt]] - data[lson[L_rt]];
        if (data_lc >= k)
            return Query(lson[L_rt], lson[R_rt], l, mid, k);
        else
            return Query(rson[L_rt], rson[R_rt], mid+1, r, k-data_lc);
    }
}tree;


struct suffix{

    int c[maxn],sa[maxn],t1[maxn],t2[maxn],m,n,h[maxn],height[maxn],rk[maxn],s[maxn];

    void Build_SA(int len){
        m = 0;
        int* x = t1,*y = t2;
        n = len;
        for( int i = 0;i < n;i++ ) m = max( m,s[i] );
        for( int i = 0;i <= m;i++ ) c[i] = 0;
        for( int i = 0;i < n;i++ ) c[ x[i] = s[i] ]++;
        for( int i = 1;i <= m;i++ ) c[i] += c[i-1];
        for( int i = n-1;i >= 0;i-- ) {
            sa[ --c[ x[i] ] ] = i;
        }
        for( int k = 1;k < n;k <<= 1 ){
            int cnt = 0;
            for( int i = n - 1;i >= n-k;i-- ) y[cnt++] = i;
            for( int i = 0;i < n;i++ ) if( sa[i] >= k ) y[cnt++] = sa[i]-k;
            for( int i = 0;i <= m;i++ ) c[i] = 0;
            for( int i = 0;i < n;i++ ) c[ x[i] ]++;
            for( int i = 1;i <= m;i++ ) c[i] += c[i-1];
            for( int i = cnt-1;i >= 0;i-- ) sa[ --c[ x[ y[i] ] ] ] = y[i];
            swap( x,y );
            int num = 0;
            x[ sa[0] ] = 0;
            for( int i = 1;i < n;i++ ){
                if( y[ sa[i-1] ] != y[ sa[i] ] || y[ sa[i-1]+k ] != y[ sa[i]+k ] ){
                    x[ sa[i] ] = ++num;
                }else{
                    x[ sa[i] ] = num;
                }
            }
            if( num == n-1 ) return;
            m = num;
        }
    }
    void getheight(){
        for( int i = 0;i < n;i++ ){
            rk[ sa[i] ] = i;
        }
        int cnt = 1;
        h[ sa[0] ] = 0;
        height[ 0 ] = 0;
        for( int i = 0;i < n;i++ ){
            if(cnt)cnt--;
            while(  rk[i] >= 1 && i + cnt < n &&sa[rk[i]-1]+cnt < n  && s[ sa[rk[i]-1]+cnt ] == s[ i+cnt ] ) cnt++;
            h[ i ] = cnt;
            height[ rk[i] ] = cnt;
        }
        //cout << "debug" << endl;
    }

}g;
int rmq[maxn][20],lg[maxn];
void init( int s,int t ){
    lint dt = t-s+1;
    lg[1] = 0;
    for( lint i = 2;i <= dt;i++ ) lg[i] = i&(i-1) ? lg[i-1] : lg[i-1] + 1;
}
void build2( int s,int t,int rmq[][20] ){
    int dt = t-s;
    for( int i = s;i < t;i++ ){
        rmq[i][0] = g.height[i];
    }
    for( int i = 1;i <= lg[dt];i++ ){
        for( int j = s;j  <= t;j++ ){
            if( j+(1<<i)-1 > t ) continue;
            rmq[j][i] = min( rmq[j][ i-1 ],rmq[ j + (1 << i-1  ) ][ i-1 ] );
        }
    }
}
lint len;
int lcp( int x,int y,int rmq[][20] ){  // x和y为排名,输出 x和y 的lcp
    x++; y++;
    if( x > y ) swap( x,y );
    if( x >= len || y > len ) return 0;
    int k = lg[y-x];
    return min( rmq[x][k],rmq[ y - ( 1 << k ) ][k] );
}
int n;
vector<int> ve;
int solve( int l,int r,int k ){
    int pos = g.rk[l-1];
    int len = r-l+1;
    int fi,en;
    int L = -1,R = pos;
    while(L!=R-1){
        int mid =L+R>>1;
        if( lcp( mid,pos,rmq ) < len ){
            L = mid;
        }else R = mid;
    }
    fi = R;
    L = pos,R = n;
    while(L!=R-1){
        int mid = L+R>>1;
        if(lcp( pos,mid,rmq ) < len ){
            R = mid;
        }else L = mid;
    }
    en = R;
    if( en-fi < k ) return -1;
    int res = tree.Query(tree.roots[fi+1-1], tree.roots[en+1-1], 1, n, k);
    return res;
}
char s[maxn];
int a[maxn];
int main()
{
    int T;
    scanf("%d",&T);
    init( 0,100004 );
    while(T--){
        int q;
        scanf("%d%d",&n,&q);len = n;
        scanf("%s",s);
        for( int i= 0;i < n;i++ ){
            g.s[i] = s[i];
        }
        g.Build_SA(n);g.getheight();
        for( int i = 1;i <= n;i++ ){
            a[i] = g.sa[i-1]+1;
        }
        //from 1
        tree.Init(a, n, n);
        build2( 0,n,rmq );
        int l,r,k;
        for( int i = 1;i <= q;i++ ){
            scanf("%d%d%d",&l,&r,&k);
            int pos = solve( l,r,k );
            printf("%d\n",pos);
        }
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值