K-th occurrence

K-th occurrence

Time Limit: 5000/5000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 461    Accepted Submission(s): 125


Problem Description
You are given a string  S consisting of only lowercase english letters and some queries.

For each query (l,r,k), please output the starting position of the k-th occurence of the substring SlSl+1...Sr in S.
 
Input
The first line contains an integer  T(1T20), denoting the number of test cases.

The first line of each test case contains two integer N(1N105),Q(1Q105), denoting the length of S and the number of queries.

The second line of each test case contains a string S(|S|=N) consisting of only lowercase english letters.

Then Q lines follow, each line contains three integer l,r(1lrN) and k(1kN), denoting a query.

There are at most 5 testcases which N is greater than 103.
 
Output
For each query, output the starting position of the k-th occurence of the given substring.

If such position don't exists, output  1 instead.
 
Sample Input
2 12 6 aaabaabaaaab 3 3 4 2 3 2 7 8 3 3 4 2 1 4 2 8 12 1 1 1 a 1 1 1
 
Sample Output
5 2 -1 6 9 8 1
#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int maxn = (1e5 + 10) * 100;
int M = 30;
int T, n, q, len, tot;
char s[maxn];
int sa[maxn], height[maxn];
int rk[maxn], tp[maxn];
int str[maxn], ton[maxn], root[maxn];
int f[300600][36];
struct tree {
    int l, r, val;
} c[maxn];

inline void rsort() {
    for (register int i = 0; i <= M; ++i)ton[i] = 0;
    for (register int i = 1; i <= len; ++i)ton[rk[i]]++;
    for (register int i = 1; i <= M; ++i)ton[i] = ton[i] + ton[i - 1];
    for (register int i = len; i >= 1; --i)sa[ton[rk[tp[i]]]--] = tp[i];
}

inline void get_height() {
    len++;
    for (register int i = 1; i <= len; ++i)rk[i] = str[i], tp[i] = i;
    rsort();
    for (register int w = 1, p = 0; p < len && w <= len; M = p, w *= 2) {
        p = 0;
        for (register int i = len - w + 1; i <= len; ++i)tp[++p] = i;
        for (register int i = 1; i <= len; ++i) {
            if (sa[i] > w) {
                tp[++p] = sa[i] - w;
            }
        }
        rsort();
        swap(rk, tp);
        rk[sa[1]] = p = 1;
        for (register int i = 2; i <= len; ++i) {
            rk[sa[i]] = (tp[sa[i - 1]] == tp[sa[i]] && tp[sa[i - 1] + w] == tp[sa[i] + w]) ? p : ++p;
        }
        if (p >= len)break;
        //printf("%d\n",p);
    }
//    for (register int i = 1; i <= n; ++i) {
//        printf("sa[ %d ] = %d\n", i, sa[i]);
//    }
    int cur_len = len;
    cur_len--;
    int k = 0;
    for (register int i = 1; i <= len; ++i)rk[sa[i]] = i;
//    for(register int i=1;i<=len;++i){
//        printf("rk[ %d ] = %d\n", i, rk[i]);
//    }
    for (register int i = 1; i <= cur_len; ++i) {
        if (k)--k;
        else k = 0;
        int j = sa[rk[i] - 1];
        while (str[i + k] == str[j + k])k++;
        height[rk[i]] = k;
    }
}

inline void init() {
    for (register int i = 1; i <= len; ++i)f[i][0] = height[i];
    for (register int j = 1; j <= 23; ++j) {
        for (register int i = 1; i + (1 << j) - 1 <= len; ++i) {
            f[i][j] = min(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
        }
    }
}

inline int query(int l, int r) {
    int cur = log2(r - l + 1.0);
    return min(f[l][cur], f[r - (1 << cur) + 1][cur]);
}

inline int update(int pre, int l, int r, int pos) {
    int nx = ++tot;
    c[nx] = c[pre];
    c[nx].val++;
    if (l == r)return nx;
    int mid = l + r >> 1;
    if (pos <= mid) {
        c[nx].l = update(c[pre].l, l, mid, pos);
    } else {
        c[nx].r = update(c[pre].r, mid + 1, r, pos);
    }
    return nx;
}

inline int query(int pl, int pr, int l, int r, int val) {
    if (l == r)return l;
    int mid = l + r >> 1;
    if (c[c[pr].l].val - c[c[pl].l].val >= val) {
        return query(c[pl].l, c[pr].l, l, mid, val);
    } else {
        return query(c[pl].r, c[pr].r, mid + 1, r, val - (c[c[pr].l].val - c[c[pl].l].val));
    }
}

int main() {
    //freopen("1.txt", "r", stdin);
    scanf("%d", &T);
    while (T--) {
        tot = 0;
        scanf("%d%d", &n, &q);
        scanf("%s", s + 1);
        len = strlen(s + 1);
        for (register int i = 0; i <= len + 1; ++i)root[i] = 0;
        M = 30;
        //printf("debug len = %d\n",len);
        for (register int i = 1; i <= len; ++i)str[i] = s[i] - 'a' + 1;
        str[len + 1] = 0;
        get_height();
        init();
        for (register int i = 1; i <= len + 1; ++i) {
            root[i] = update(root[i - 1], 1, n, sa[i]);
            //printf("debug root[%d] = %d\n",i,root[i]);
        }
        int l, r, k;
        while (q--) {
            scanf("%d%d%d", &l, &r, &k);
            int siz = r - l + 1;
            //printf("debug rk[l] = %d\n",rk[l]);
            l = rk[l];

            int L = 1, R = l, ans_l, ans_r;
            while (L <= R) {
                int mid = L + R >> 1, cur;
                cur = 100000;
                if (mid + 1 <= l) cur = query(mid + 1, l);
                if (cur >= siz) {
                    ans_l = mid;
                    R = mid - 1;
                } else {
                    L = mid + 1;
                }
//                cur = query(mid, l);
//                if (cur >= siz) {
//                    ans_l = mid;
//                    R = mid - 1;
//                } else {
//                    L = mid + 1;
//                }
            }
            //printf("debug ans_l = %d\n",ans_l);
            L = l, R = len;
            while (L <= R) {
                int mid = L + R >> 1, cur;
                cur = 100000;
                if (l + 1 <= mid) cur = query(l + 1, mid);
                if (cur >= siz) {
                    ans_r = mid;
                    L = mid + 1;
                } else {
                    R = mid - 1;
                }
//                cur = query(l, mid);
//                if (cur >= siz) {
//                    ans_l = mid;
//                    R = mid - 1;
//                } else {
//                    L = mid + 1;
//                }
            }
//            int pos = rk[l - 1];
//            int L = 1, R = pos, LL = pos, RR = pos;
//            while (L < R) {
//                int mid = (L + R) / 2;
//                if (query(mid, pos) >= r - l + 1)
//                    R = mid;
//                else
//                    L = mid + 1;
//            }
//            if (query(L, pos) >= r - l + 1)
//                LL = L - 1;
//            if (pos < n - 1) {
//                pos++;
//                L = pos, R = n - 1;
//                while (L < R) {
//                    int mid = (L + R) / 2;
//                    if (query(pos, mid) >= r - l + 1)
//                        L = mid + 1;
//                    else
//                        R = mid;
//                }
//                if (query(pos, L) < r - l + 1)
//                    L--;
//                if (L >= pos && query(pos, L) >= r - l + 1)
//                    RR = L;
//            }
            //printf("debug ans_l = %d ans_r = %d\n",ans_l,ans_r);
            if (ans_r - ans_l + 1 < k) {
                puts("-1");
            } else {
                printf("%d\n", query(root[ans_l - 1], root[ans_r], 1, n, k));
            }
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/czy-power/p/11404138.html