zoukankan      html  css  js  c++  java
  • HDU-6704 K-th occurrence

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

    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.

    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(1≤l≤r≤N) and k(1≤k≤N), denoting a query.

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

    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
    

    题解

    给定一个字符串,每次询问[l,r]的字符串第k次出现的位置,没有则输出-1

    后缀数组理解深刻的话应该可以秒掉这道题

    首先,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
    ", query(T[tl - 1], T[tr], 1, n, k));
            }
        }
        return 0;
    }
    
  • 相关阅读:
    pytest框架运用
    unitTest学习
    发送邮件
    python 连接远程服务器,修改时间
    Redis基础
    django 知识点扩展
    ACM 题目 1487: [蓝桥杯][算法提高VIP]不同单词个数统计
    Leetcode 面试题 08.01. 三步问题
    Leetocode 198. 打家劫舍
    Leetcode 121. 买卖股票的最佳时机
  • 原文地址:https://www.cnblogs.com/artoriax/p/11452775.html
Copyright © 2011-2022 走看看