2019CCPC qualifying network 1003 K-th occurrence suffix automaton + + Chairman binary tree

Question is intended: to give you a string of length n, there are m times asked each time to the position of the substring interrogation l r occurring in the k-th original string, -1 if no output. n, m are 1e5 level.

Ideas: regret not learn suffix array QAQ, in fact, as long as the suffix array learned this question quite a miss. This problem can be converted into the number of suffixes and suffix lcp length l is greater than or equal r - l + 1. We know that, in the suffix array, two suffixes i, j is the lcp min (height [rank [j] + 1], height [rank [j] + 2], .... height [rank [i]] ). So, we can separate the two left most position (assuming that this position is p), the position to the rank [l] is the height> = r - l + 1, i.e. from p to rank [l] these locations suffix and lcp is greater than or equal length l r - l + 1 is. The right rank [l] can be obtained in the same way. So, we can know what suffix may be the answer. Then there is a problem, how do you know they are in the k-th position it? This is a big problem k-static range, we sa [i] in order to insert Chairman tree, and then ask the k-large positions can be dichotomized between two endpoints separated.

Code (suffix array board copy online QAQ):

#include <bits / STDC ++ H.> 
the using namespace STD; 
const int MAXN = 100010; 
char S [MAXN]; 
int n-, TOT; 
int the root [MAXN]; 
struct Node { 
    int SUM; 
    int LC, RC; 
}; 
Node TR [MAXN * 50]; 
struct SA { 
    int SA [MAXN], X [MAXN], Y [MAXN], C [MAXN]; 
    int Rank [MAXN], height [MAXN], H [MAXN]; 
    int F [ MAXN] [18 is]; 
    
    void build_sa (int m) { 
        for (int I = 0; I <= m; I ++) C [I] = 0; 
        for (int I =. 1; I <= n-; ++ I) C ++ [X [i] = S [i]]; 
    // C is the array tub 
    // x [i] is the i-th element of the first key 
        for (int i = 2; i <= m; + i +) c [i] + = c [i-1]; 
    // prefix and c do, we can draw up to each keyword is the first of several
        for (int I = n-; I> =. 1; Inc. (www.i-levelmedia.com)) SA [C [X [I]] -] = I; 
            for (int i = 2; i <= m; ++ i) c [i] + = c [i- 1]; // first keyword ranking 1 to the number of how many i
        for (int. 1 = K; K <= n-; = K <<. 1) { 
            int NUM = 0; 
            for (int I = n-K-+. 1; I <= n-; I ++) Y [NUM ++] i =; 
    // Y [i] represents a second keyword ranking number i, the position of the first keyword 
    // n-k + 1 of the n-th bit to the second keyword is therefore not in the front rank 
            for (int i =. 1; i <= n-; i ++) iF (SA [i]> K) Y [NUM ++] = SA [i] -k; 
    // rank i is the number in the array in the k-th bit after 
    // If the condition (sa [i]> k) then it may be used as the second key others, which put the first keyword position on the line y add 
    // so enumeration i is the second key, the second key to the front enqueued 
            for (int i =. 1; I <= m; I ++) c [I] = 0; 
    // initialize c tub 
            for (int i . 1 =; <= n-I; I ++) ++ C [X [I]]; 
    // because the last time the cycle has been calculated so that the first keyword directly added on the list 
    // y is because the order of the second keyword according to order row 
    after // second keyword rearward, in the same first keyword ranked by the bucket
            for (int I = n-; I> =. 1; Inc. (www.i-levelmedia.com)) SA [C [X [Y [I]]] -] = Y [I], Y [I] = 0; 
        for (int I =. 1; I <= n-; I ++) {
    // radix sort 
            swap (x, the y-); 
    // here do not think too much, because you want to use to generate the old, put the old copy down when the new x, no other meaning 
            x [sa [1]] . 1 =; 
            NUM =. 1; 
            for (int I = 2; I <= n-; I ++) 
                X [SA [I]] = (Y [SA [I]] == Y [SA [-I. 1]] the y-&& [sa [i] + k] the y-== [SA [i-1] + k]) NUM:? NUM ++; 
    // because sa [i] is already sorted, so you can enumerate by rating , generating a first key under the 
            IF (== n-NUM) BREAK; 
            m = NUM; 
    // here that not 122, because there are a number of new 
        } 
    } 
    
    void get_height () { 
        int K = 0; 
        for (int I =. 1; I <= n-; I ++) Rank [SA [I]] = I; 
            IF (Rank [I] ==. 1) Continue; // first height is 0 
            IF (K) - K; // H [I]> = H [. 1-I] -1; 
            int J = SA [Rank [I] -1];
            while (j+k<=n && i+k<=n && s[i+k]==s[j+k]) ++k;
            height[rank[i]]=k;//h[i]=height[rk[i]];
        }
        for (int i = 1; i <= n; i++) h[i] = height[rank[i]];
    }
    
    void build_st() {
        for (int i = 1; i <= n; i++)
            f[i][0] = height[i];
        int t = log(n) / log(2) + 1;
        for (int j = 1; j < t; j++) {
            for (int i = 1; i <= n - (1 << j) + 1; i++)
                f[i][j] = min(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
        }
    }
    
    int query(int l, int r) {
        if(l > r) return 0;
        int k = log(r - l + 1) / log(2);
        return min(f[l][k], f[r - (1 <<k) + 1] [k]);
    }
};

SA solve;

int build(int l, int r) {
    int p = ++tot;
    if (l == r) {
        tr[p].sum = 0;
        tr[p].lc = tr[p].rc = 0;
        return p;
    }
    int mid = (l + r) >> 1;
    tr[p].lc = build(l, mid);
    tr[p].rc = build(mid + 1, r);
    tr[p].sum = tr[tr[p].lc].sum + tr[tr[p].rc].sum;
    return p;
}
int insert(int now, int l, int r, int x, int val) {
    int p = ++tot;
    tr[p] = tr[now];
    if(l == r) {
        tr[p].sum = 1;
        return p;
    }
    int mid = (l + r) >> 1;
    if(x <= mid) tr[p].lc = insert(tr[now].lc, l, mid, x, val);
    else tr[p].rc = insert(tr[now].rc, mid + 1, r, x, val);
    tr[p].sum = tr[tr[p].lc].sum + tr[tr[p].rc].sum;
    return p;
}
int query(int lnow, int rnow, int l, int r, int remain) {
    if(l > r) return 0;
    if(l == r) {
        return l;
    }
    int mid = (l + r) >> 1;
    int tmp = tr[tr[rnow].lc].sum - tr[tr[lnow].lc].sum;
    if(tmp >= remain) return query(tr[lnow].lc, tr[rnow].lc, l, mid, remain);
    else return query(tr[lnow].rc, tr[rnow].rc, mid + 1, r, remain - tmp); 
}
int main() {
    int T, m, l, r, k, ql, qr;
//    freopen("cin.txt", "r", stdin);
//    freopen("cout.txt", "w", stdout);
    scanf("%d", &T);
    while(T--) {
        tot = 0;
        scanf("%d%d", &n, &m);
        scanf("%s", s + 1);
        for (int i = 1; i <= n; i++)
            s[i] -= ('a' - 1);
        solve.build_sa(30);
        solve.get_height();
        solve.build_st();
        root[0] = build(1, n);
        for (int i = 1; i <= n; i++) {
            root[i] = insert(root[i - 1], 1, n, solve.sa[i], 1);
        }
        for (int i = 1; i <= m; i++) {
            scanf("%d%d%d", &l, &r, &k);
            int p = solve.rank[l];
            int L = 1, R = p;
            while(L < R) {
                int mid = (L + R) >> 1;
                if(solve.query(mid + 1, p) < r - l + 1) L = mid + 1;
                else R = mid;
            }
            ql = L;
            L = p, R = n;
            while(L < R) {
                int mid = (L + R + 1) >> 1;
                if(solve.query(p + 1, mid) < r - l + 1) R = mid - 1;
                else L = mid;
            }
            qr = R;
            if(qr - ql + 1 < k) printf("-1\n");
            else printf("%d\n", query(root[ql - 1], root[qr], 1, n, k));
        }
    }
    
}

  

Guess you like

Origin www.cnblogs.com/pkgunboat/p/11407332.html