HDU-6704 K-th occurrence

Description

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

For each query (l,r,k), please output the starting position of the k-th occurence of the substring $S_lS_{l+1}...S_r $in S.數組

Input

The first line contains an integer T(1≤T≤20), denoting the number of test cases.ui

The first line of each test case contains two integer N(1≤N≤\(10^5\)),Q(1≤Q≤\(10^5\)), denoting the length of S and the number of queries.spa

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

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

There are at most 5 testcases which N is greater than \(10^3\).ip

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.get

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

題解

給定一個字符串,每次詢問[l,r]的字符串第k次出現的位置,沒有則輸出-1input

後綴數組理解深入的話應該能夠秒掉這道題

首先,height[i]表示排名第i位的和第i-1位的最長公共前綴,因此咱們要找某個子串出現的全部位置,只須要在height數組中二分,詢問的字串所處後綴的排名即爲\(rk[l]\),那麼咱們從\(rk[l]\)開始向上向下二分,讓這段的區間height最小值大於r-l+1,那麼他們就都有r-l+1的最長公共前綴,咱們找出這個邊界後,用主席樹求這個區間中sa數組的第k大便可。

AC代碼

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
typedef long long ll;
char s[N];
int x[N], y[N], c[N], sa[N], rk[N], height[N];
int n, m, q;
void tsort() {
    for (int i = 0; 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];
}
void get_sa() {
    memset(c, 0, sizeof(c));
    memset(x, 0, sizeof(x));
    memset(y, 0, sizeof(y));
    for (int i = 1; i <= n; i++) x[i] = s[i], y[i] = i;
    tsort();
    for (int k = 1; k <= n; k <<= 1) {
        int num = 0;
        for (int i = n - k + 1; i <= n; i++) y[++num] = i;
        for (int i = 1; i <= n; i++) if (sa[i] > k) y[++num] = sa[i] - k;
        tsort();
        swap(x, y);
        x[sa[1]] = 1;
        num = 1;
        for (int i = 2; i <= n; i++)
            x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) ? num : ++num;
        if (num == n) break;
        m = num;
    }
}
void get_h() {
    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 (s[i + k] == s[j + k]) k++;
        height[rk[i]] = k;
    }
}
int st[N][20], lg2[N];
void ST() {
    for (int i = 1; i <= n; i++) {
        st[i][0] = height[i];
    }
    for (int j = 1; (1 << j) <= n; j++) {
        for (int i = 1; (i + (1 << j) - 1) <= n; i++) {
            st[i][j] = min(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
        }
    }
    for (int i = 2; i <= n; i++) {
        lg2[i] = lg2[i >> 1] + 1;
    }
}
int rmq(int l, int r) {
    if (l > r)
        return 0;
    else {
        int x = lg2[r - l + 1];
        return min(st[l][x], st[r - (1 << x) + 1][x]);
    }
}
int L[N * 40], R[N * 40], T[N], cnt;
ll sum[N * 40];
int build(int l, int r) {
    int rt = ++cnt;
    sum[rt] = 0;
    int mid = (l + r) >> 1;
    if (l < r) {
        L[rt] = build(l, mid);
        R[rt] = build(mid + 1, r);
    }
    return rt;
}
int update(int pre, int l, int r, int x) {
    int rt = ++cnt;
    int mid = (l + r) >> 1;
    L[rt] = L[pre], R[rt] = R[pre], sum[rt] = sum[pre] + 1;
    if (l < r) {
        if (x <= mid) L[rt] = update(L[pre], l, mid, x);
        else R[rt] = update(R[pre], mid + 1, r, x);
    }
    return rt;
}
int query(int u, int v, int l, int r, int k) {
    if (l >= r) {
        return l;
    }
    int mid = (l + r) >> 1;
    int x = sum[L[v]] - sum[L[u]];
    if (x >= k) return query(L[u], L[v], l, mid, k);
    else {
        if (sum[R[v]] - sum[R[u]] < k - x) return -1;
        return query(R[u], R[v], mid + 1, r, k - x);
    }
}
int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        m = 130;
        scanf("%d%d", &n, &q);
        scanf("%s", s + 1);
        cnt = 0;
        get_sa();
        get_h();
        ST();
        T[0] = build(1, n);
        for (int i = 1; i <= n; i++) {
            T[i] = update(T[i - 1], 1, n, sa[i]);
        }
        while (q--) {
            int l, r, k;
            scanf("%d%d%d", &l, &r, &k);
            int tl = rk[l], tr = rk[l];
            int x = 1, y = rk[l];
            while (x <= y) {
                int mid = (x + y) >> 1;
                if (rmq(mid, rk[l]) >= r - l + 1) {
                    y = mid - 1;
                    tl = min(tl, mid - 1);//注意細節
                }
                else x = mid + 1;
            }
            x = rk[l] + 1, y = n;//注意細節
            while (x <= y) {
                int mid = (x + y) >> 1;
                if (rmq(rk[l] + 1, mid) >= r - l + 1) {
                    x = mid + 1;
                    tr = max(tr, mid);
                }
                else y = mid - 1;
            }
            printf("%d\n", query(T[tl - 1], T[tr], 1, n, k));
        }
    }
    return 0;
}
相關文章
相關標籤/搜索