HDU-6704 K-th occurrence (+ suffix array Chairman tree)

The meaning of problems

Given a string of length n, Q interrogation times, each query \ ((L, R & lt, K) \) , the answer substring \ (s_ls_ {l + 1} \ cdots s_r \) of \ (K \) occurrences of the position, if there outputs -1. \ (n \ le 1e5, Q \ le 1e5 \)

analysis

Discover the k-th position of the substring appears, it is easy to think of a powerful tool to use string processing - suffix array.

So how to use it? Each row of a sequence we first suffix string sample, then the sample is simulated

原 串: aaabaabaaaab

Ranking suffix position
1 aaaab 8
2 AAAS 9
3 aaabaabaaab 1
4 aab 10
5 aabaaaab 5
6 aabaabaaab 2
7 from 11
8 abaaaab 6
9 Ababaab 3
10 b 12
11 baaaab 7
12 Babaab 4

Query: [3,3], k = 4

[3,3] represents the substring \ (A \) , we can find the starting position for the suffix 3 \ (t = abaabaaab \) , the first character of the substring suffix represents the current to be queried, surprise found, while the substring has appeared in some other suffixes, the suffixes of these \ (T \) of the LCP (longest common prefix) is greater than or equal to 1. In this example we can find in the rankings LCP suffix t before 9 greater than 1, so only need to find the k-large at the beginning of the suffix. That is, [8,9,1,10,5,2,11,6,3]to find the fourth largest, namely 5.

Query: [2,3], k = 2

[2,3] is a substring \ (AA \) , the start position of the suffix 2 \ (T = aabaabaaab \) , and \ (T \) the LCP is greater than the extension start position are equal to 2 [8,9,1,10,5,2], the second largest the location is 2.

So how is reflected in the program do?

Determined suffix array \ (rank, height \) array, using \ (ST \) table may be \ (O (1) \) query LCP two suffixes.

Further extension can be found in the ranking, the ranking is the suffix of the other suffix LCP x increases as the difference absolute value of rank decreases, it is possible to find a two-half interval ranking, so that all the suffixes within this range LCP and the target is greater than the length of the suffix is ​​equal to substring queries.

After finding this interval, sustainable use of the tree line to find the k-th largest value (for sa arrays) to

Complexity Analysis: seek suffix array \ (O (nlog (n) ) \) , half \ (O (nlog (n) ) \) , Chairman of the tree query k-th largest value \ (O (nlog (n) ) \)

Overall complexity \ (O (nlog (n) ) \)

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
const int MAXN = N;
char s[N];
int sa[N],x[N],y[N],c[N],rk[N],h[N],n,q;
int len, cnt;
int a[MAXN];
int b[MAXN];
int t[MAXN];
int ls[MAXN * 40];
int rs[MAXN * 40];
int sum[MAXN * 40];
int build(int l, int r) {
    int rt = ++cnt;
    int mid = l + r >> 1;
    sum[rt] = 0;
    if(l < r) {
        ls[rt] = build(l, mid);
        rs[rt] = build(mid + 1, r);
    }
    return rt;
}
int add(int o, int l, int r, int k) {
    int rt = ++cnt;
    int mid = l + r >> 1;
    ls[rt] = ls[o]; rs[rt] = rs[o]; sum[rt] = sum[o] + 1;
    if(l < r)
    if(k <= mid) ls[rt] = add(ls[o], l, mid, k);
    else rs[rt] = add(rs[o], mid + 1, r, k);
    return rt;
}

int query(int ql, int qr, int l, int r, int k) {
    int x = sum[ls[qr]] - sum[ls[ql]];
    int mid = l + r >> 1;
    if(l == r) return l;
    if(x >= k) return query(ls[ql], ls[qr], l, mid, k);
    else return query(rs[ql], rs[qr], mid + 1, r, k - x);
}

void build_sa(char *s,int n,int m){
    memset(c,0,sizeof c);
    for(int i=1;i<=n;++i) ++c[x[i] = s[i]];
    for(int i=2;i<=m;++i) c[i] += c[i-1];
    for(int i=n;i>=1;--i) sa[c[x[i]]--] = i;
    for(int k=1;k<=n;k<<=1){
        int p = 0;
        for(int i=n-k+1;i<=n;++i) y[++p] = i;
        for(int i=1;i<=n;++i) if(sa[i] > k) y[++p] = sa[i]-k;
        for(int i=1;i<=m;++i) c[i] = 0;
        for(int i=1;i<=n;++i) ++c[x[i]];
        for(int i=2;i<=m;++i) c[i] += c[i-1];
        for(int i=n;i>=1;--i) sa[c[x[y[i]]]--] = y[i] , y[i] = 0;
        swap(x,y);
        x[sa[1]] = 1; p = 1;
        for(int i=1;i<=n;++i)
            x[sa[i]] = (y[sa[i]] == y[sa[i-1]] && y[sa[i] + k] == y[sa[i-1]+k] ? p : ++p);
        if(p >= n)break;
        m = p;
    }
}
void get_height(){
    int k = 0;
    for(int i=1;i<=n;++i)rk[sa[i]] = i;
    for(int i=1;i<=n;++i){
        if(rk[i] == 1)continue;
        if(k) --k;
        int j = sa[rk[i]-1];
        while(j + k <= n && i + k <= n && s[i+k] == s[j+k])++k;
        h[rk[i]] = k;
    }
}
int mm[N];
int best[20][N];
void initRMQ(int n){
    mm[0] = -1;
    for(int i=1;i<=n;i++)
        mm[i] = ((i & (i-1)) == 0) ? mm[i-1] + 1 : mm[i-1];
    for(int i=1;i<=n;i++)best[0][i] = i;
    for(int i=1;i<=mm[n];i++)
        for(int j=1;j+(1<<i)-1<=n;j++){
            int a = best[i-1][j];
            int b = best[i-1][j+(1<<(i-1))];
            if(h[a] < h[b])best[i][j] = a;
            else best[i][j] = b;
        }
}
int askRMQ(int a,int b){
    int t = mm[b-a+1];
    b -= (1<<t) - 1;
    a = best[t][a];b = best[t][b];
    return h[a] < h[b] ? a : b;
}
int lcp(int a,int b){
    if(a == b)return n;
    if(a > b)swap(a,b);
    return h[askRMQ(a+1,b)];
}
int getL(int l,int r,int len,int x){
    while(l < r){
        int mid = l + r >> 1;
        if(lcp(mid,x) < len) l = mid + 1;
        else r = mid;
    }
    return l;
}
int getR(int l,int r,int len,int x){
    while(l < r){
        int mid = (l + r + 1) >> 1;
        if(lcp(mid,x) < len) r = mid - 1;
        else l = mid;
    }
    return l;
}
int getAns(int l,int r,int k){
    return query(t[l - 1], t[r], 1, n, k);
}
int solve(int l,int r,int k){
    int len = r - l + 1;
    int L = getL(1,rk[l],len,rk[l]);//二分找区间左端点
    int R = getR(rk[l],n,len,rk[l]);//二分找区间右端点
    if(k > R-L+1) return -1;
    return getAns(L,R,k);//返回主席树查询结果
}
int main(){
    int T;scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&q);
        scanf("%s",s+1);
        build_sa(s,n,150);
        get_height();
        initRMQ(n);
        //初始化主席树
        cnt = 0;
        t[0] = build(1,n);
        for(int i=1;i<=n;i++){
            int tt = sa[i];
            t[i] = add(t[i-1],1,n,tt);
        }
        while(q --){
            int l,r,k;
            scanf("%d%d%d",&l,&r,&k);
            printf("%d\n",solve(l,r,k));
        }
    }
    return 0;
}

Guess you like

Origin www.cnblogs.com/1625--H/p/11403199.html