zoukankan      html  css  js  c++  java
  • HDU 6704 K-th occurrence(主席树 + RMQ + 后缀数组)题解

    题意:

    给一个串(S)(lengthleq 1e5)(Qleq1e5)个询问,每次询问输出和(S_lS_{l+1}dots S_r)长得一模一样的第(k)个子串的开头位置。

    思路:

    用后缀数组处理一下,那么所有相同子串最后的(sa)都会靠在一起,所以找到对应的(height)位置,然后向左向右延伸直到(LCP)长度不足(r-l+1)(RMQ)然后二分左右第一个长度比(r-l+1)小的位置),那么就找到了所有和(S_lS_{l+1}dots S_r)长得一模一样的开始位置,然后在主席树上找第(k)大。

    代码:

    #include<map>
    #include<set>
    #include<queue>
    #include<stack>
    #include<ctime>
    #include<cmath>
    #include<cstdio>
    #include<string>
    #include<vector>
    #include<cstring>
    #include<sstream>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const int maxn = 1e5 + 5;
    const int INF = 0x3f3f3f3f;
    const ull seed = 131;
    const ll MOD = 1e9;
    using namespace std;
    struct node{
        int lson, rson;
        int num;
    }T[maxn * 40];
    int root[maxn], tot;
    void init(){
        tot = 0;
        memset(T, 0, sizeof(T));
    }
    void update(int l, int r, int &now, int pre, int pos, int v){
        T[++tot] = T[pre], now = tot;
        T[now].num += v;
        if(l == r) return;
        int m = (l + r) >> 1;
        if(pos <= m)
            update(l, m, T[now].lson, T[pre].lson, pos, v);
        else
            update(m + 1, r, T[now].rson, T[pre].rson, pos, v);
    }
    int queryK(int l, int r, int now, int pre, int k){
        if(l == r) return l;
        int m = (l + r) >> 1, Lsum;
        Lsum = T[T[now].lson].num - T[T[pre].lson].num;
        if(Lsum >= k)
            return queryK(l, m, T[now].lson, T[pre].lson, k);
        else
            return queryK(m + 1, r, T[now].rson, T[pre].rson, k - Lsum);
    }
    
    
    int str[maxn];  //str[n]赋值一个最小值0,其他大于0
    int t1[maxn], t2[maxn], c[maxn];
    int sa[maxn];   //排名为i的后缀下标
    int rk[maxn];   //后缀下标为i的排名
    int height[maxn];   //sa[i]与sa[i - 1]的LCP
    bool cmp(int *r, int a, int b, int l){
        return r[a] == r[b] && r[a + l] == r[b + l];
    }
    void da(int *str, int n, int m){
        n++;
        int i, j, p, *x = t1, *y = t2;
        for(i = 0; i < m; i++) c[i] = 0;
        for(i = 0; i < n; i++) c[x[i] = str[i]]++;
        for(i = 1; i < m; i++) c[i] += c[i - 1];
        for(i = n - 1; i >= 0; i--) sa[--c[x[i]]] = i;
        for(j = 1; j <= n; j <<= 1){
            p = 0;
            for(i = n - j; i < n; i++) y[p++] = i;
            for(i = 0; i < n; i++) if(sa[i] >= j) y[p++] = sa[i] - j;
            for(i = 0; i < m; i++) c[i] = 0;
            for(i = 0; i < n; i++) c[x[y[i]]]++;
            for(i = 1; i < m; i++) c[i] += c[i - 1];
            for(i = n - 1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];
            swap(x, y);
            p = 1; x[sa[0]] = 0;
            for(i = 1; i < n; i++)
                x[sa[i]] = cmp(y, sa[i - 1], sa[i], j)? p - 1 : p++;
            if(p >= n) break;
            m = p;
        }
        int k = 0;
        n--;
        for(i = 0; i <= n; i++) rk[sa[i]] = i;
        for(i = 0; i < n; i++){
            if(k) k--;
            j = sa[rk[i] - 1];
            while(str[i + k] == str[j + k]) k++;
            height[rk[i]] = k;
        }
    }
    int n;
    int dp[maxn][20], mm[maxn];
    void initRMQ(){
        mm[0] = -1;
        for(int i = 1; i <= n; i++){
            mm[i] = ((i & (i - 1)) == 0)? mm[i - 1] + 1 : mm[i - 1];
            dp[i][0] = height[i];
        }
        for(int j = 1; j <= mm[n]; j++){
            for(int i = 1; i + (1 << j) - 1 <= n; i++){
                dp[i][j] = min(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]);
            }
        }
    }
    int rmq(int st, int en){
        int k = mm[en - st + 1];
        return min(dp[st][k], dp[en - (1 << k) + 1][k]);
    }
    int getL(int pos, int len){
        int l = 2, r = pos;
        while(l <= r){
            if(l == r){
                if(height[l] >= len) return l - 1;
                return l;
            }
            int m = (l + r) >> 1;
            if(rmq(m + 1, r) < len){
                l = m + 1;
            }
            else{
                r = m;
            }
        }
    }
    int getR(int pos, int len){
        int l = pos, r = n;
        while(l <= r){
            if(l == r){
                if(height[l] >= len) return l;
                return l - 1;
            }
            int m = (l + r) >> 1;
            if(rmq(l, m) < len){
                r = m;
            }
            else{
                l = m + 1;
            }
        }
    }
    int m;
    char s[maxn];
    int main(){
        int T;
        scanf("%d", &T);
        while(T--){
            scanf("%d%d", &n, &m);
            scanf("%s", s);
            int LEN = 0;
            for(int i = 0; i < n; i++){
                str[LEN++] = s[i] - 'a' + 1;
            }
            str[LEN] = 0;
            da(str, LEN, 30);
    
    //        for(int i = 1; i <= n; i++){
    //            printf("%2d * ", i);
    //            for(int j = sa[i]; j < LEN; j++){
    //                printf("%c", str[j] - 1 + 'a');
    //            }
    //            puts("");
    //        }
    
            init();
            initRMQ();
            for(int i = 1; i <= n; i++){
                update(1, n, root[i], root[i - 1], sa[i] + 1, 1);
            }
            while(m--){
                int l, r, k;
                scanf("%d%d%d", &l, &r, &k);
                l--, r--;
                if(n == 1){
                    if(k == 1) printf("1
    ");
                    else printf("-1
    ");
                    continue;
                }
    
    
                int len = r - l + 1;
                if(rk[l] == 1){
                    if(height[2] < len && k == 1) printf("%d
    ", l + 1);
                    else if(height[2] < len) printf("-1
    ");
                    else{
                        int pos = 2;
                        int pl = getL(pos, len), pr = getR(pos, len);
    
                        if(pr - pl + 1 < k) printf("-1
    ");
                        else printf("%d
    ", queryK(1, n, root[pr], root[pl - 1], k));
                    }
                }
                else if(rk[l] == n){
                    if(height[n] < len && k == 1) printf("%d
    ", l + 1);
                    else if(height[n] < len) printf("-1
    ");
                    else{
                        int pos = n;
                        int pl = getL(pos, len), pr = getR(pos, len);
    
                        if(pr - pl + 1 < k) printf("-1
    ");
                        else printf("%d
    ", queryK(1, n, root[pr], root[pl - 1], k));
    
                    }
                }
                else{
                    if(max(height[rk[l]], height[rk[l] + 1]) < len && k == 1) printf("%d
    ", l + 1);
                    else if(max(height[rk[l]], height[rk[l] + 1]) < len) printf("-1
    ");
                    else{
                        int pos = height[rk[l]] > height[rk[l] + 1]? rk[l] : rk[l] + 1;
                        int pl = getL(pos, len), pr = getR(pos, len);
    
                        if(pr - pl + 1 < k) printf("-1
    ");
                        else printf("%d
    ", queryK(1, n, root[pr], root[pl - 1], k));
    
                    }
                }
    
            }
        }
        return 0;
    }
    
    
  • 相关阅读:
    IPC——信号量
    IPC——命名管道
    IPC——匿名管道
    IPC——信号
    管道和命名管道
    Oracle业务用户密码过期问题的解决
    Oracle获取数据库中的对象创建语句
    RAC禁用DRM特性
    配置Server Side TAF
    同一环境下新建Standby RAC库
  • 原文地址:https://www.cnblogs.com/KirinSB/p/11424053.html
Copyright © 2011-2022 走看看