hdu6704 K-th occurrence(后缀数组+RMQ+主席树)

题意

给定一个长度为 (n) 的字符串,有 (q) 次询问,每次询问求字符串的 ([l, r]) 所形成的子串第 (k) 次出现时的位置。

传送门

思路

([l, r]) 形成的子串,它是一些后缀的前缀,并且这些前缀在后缀数组中的rk是相邻的,因此,对于([l, r]) 我们可以通过 rmq/lcp 求出他的区间公共前缀长度,之后二分长度大于等于 (r-l+1) 的左右端点,只需要求出这些端点的第 (k) 小就可以,对于这些端点,可以通过主席树维护 (sa[i]) ,之后就可以 (O(log)) 查询第K小了 。

Code

#include <bits/stdc++.h>

using namespace std;
const int maxn = 1e5+10;
const int maxm = maxn*20;

int n;
char str[maxn];
struct node {
    int l, r, val;
}tr[maxm];
namespace HJTree {
    int tot = 0;

    void init() { tot = 0; }

    void build(int l, int r, int &x) {
        x = ++tot;
        tr[x].val = 0;
        if(l==r) return;
        int mid = l+r>>1;
        build(l, mid, tr[x].l);
        build(mid+1, r, tr[x].r);
    }

    void update(int l, int r, int x, int &y, int p) {
        y = ++tot;
//        cout << l << " " << r << " " << x << " " << y << " " << p << endl;
        tr[y] = tr[x];
        ++tr[y].val;
        if(l==r) return;
        int mid = l+r >> 1;
        if(p <= mid) update(l, mid, tr[x].l, tr[y].l, p);
        else update(mid+1, r, tr[x].r, tr[y].r, p);
    }

    int query(int l, int r, int x, int y, int k) {
        if(l==r) return l;
        int mid = l+r>>1;
        int tmp = tr[tr[y].l].val - tr[tr[x].l].val;
        if(tmp >= k) return query(l, mid, tr[x].l, tr[y].l, k);
        return query(mid+1, r, tr[x].r, tr[y].r, k-tmp);
    }
}

struct SuffixArray {
    int x[maxn], y[maxn], c[maxn];
    int sa[maxn], rk[maxn], height[maxn];

    void SA() {
        int m = 26;
        for (int i=0; i<=m; ++i) c[i] = 0;
        for (int i=1; i<=n; ++i) ++c[(x[i] = str[i]-'a')];
        for (int i=1; i<=m; ++i) c[i] += c[i-1];
        for (int i=n; i>=1; --i) sa[c[x[i]]--] = i;

        for (int p, k=1; k<=n; k<<=1) {
            p = 0;
            for (int i=n; i>n-k; --i) y[++p] = i;
            for (int i=1; i<=n; ++i) {
                if(sa[i]>k)
                    y[++p] = sa[i]-k;
            }
            for (int i=0; i<=m; ++i) c[i] = 0;
            for (int i=1; i<=n; ++i) ++c[x[y[i]]];
            for (int i=1; i<=m; ++i) c[i] += c[i-1];
            for (int i=n; i>=1; --i) sa[c[x[y[i]]]--] = y[i];

            p = y[sa[1]] = 1;
            for (int a, b, i=2; i<=n; ++i) {
                a = sa[i]+k>n? -1: x[sa[i]+k];
                b = sa[i-1]+k>n? -1: x[sa[i-1]+k];
                y[sa[i]] = (x[sa[i]]==x[sa[i-1]] && a==b)? p: ++p;
            }
            swap(x, y);
            if(p>=n) break;
            m = p;
        }
        for (int i=1; i<=n; ++i) rk[i] = x[i];
    }

    void getHeight() {
        int k = 0;
        for (int i=1; i<=n; ++i) {
            if(k) --k;
            int j = sa[rk[i]-1];
            while(str[i+k] == str[j+k]) ++k;
            height[rk[i]] = k;
        }
    }

    int root[maxn];
    int st[maxn][20];

    void build() {
        SA();
        HJTree::init();
        HJTree::build(1, n, root[0]);
        for (int i=1; i<=n; ++i) HJTree::update(1, n, root[i-1], root[i], sa[i]);
    }

    void ST() {
        getHeight();
//        for (int i=1; i<=n; ++i) printf("%d ", sa[i]); puts("");
//        for (int i=1; i<=n; ++i) printf("%d ", rk[i]); puts("");
//        for (int i=1; i<=n; ++i) printf("%d ", height[i]); puts("");
        for (int i=1; i<=n; ++i) st[i][0] = height[i];
        for (int j=1; j<=20; ++j) {
            int p = 1<<j-1, l = (1<<j)-1;
            for (int i=1; i+l<=n; ++i)
                st[i][j] = min(st[i][j-1], st[i+p][j-1]);
        }
    }

    int rmq(int l, int r) {
        if(l==r) return 0x3f3f3f3f;
        ++l;
        int len = r-l+1, d=0;
        while((1<<d+1)<=len) ++d;
        int p = 1<<d;
        return min(st[l][d], st[r-p+1][d]);
    }

    int findL(int pos, int len) {
        int l = 1, r = pos;
        while (l <= r) {
            int mid = l + r >> 1;
            if (rmq(mid, pos) < len) l=mid+1;
            else r=mid-1;
        }
        return l;
    }

    int findR(int pos, int len) {
        int l = pos, r = n;
        while (l <= r) {
            int mid = l + r >> 1;
            if (rmq(pos, mid) < len) r=mid-1;
            else l=mid+1;
        }
        return r;
    }

    int query(int l, int r, int k) {
        int len = r-l+1;
        int pos = rk[l];
//        cout << pos << " " << len << " ";
        int L = findL(pos, len);
        int R = findR(pos, len);
//        cout << L << " " << R << endl;
        if(R-L+1<k) return -1;
        return HJTree::query(1, n, root[L-1], root[R], k);
    }
}suffixArray;

int T, q;
int main() {
    scanf("%d", &T);
    while(T--) {
        scanf("%d%d", &n, &q);
        scanf("%s", str+1);
        suffixArray.build();
        suffixArray.ST();
        for (int l, r, k, i=1; i<=q; ++i) {
            scanf("%d%d%d", &l, &r, &k);
            printf("%d
", suffixArray.query(l, r, k));
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/acerkoo/p/11409700.html