其他分享
首页 > 其他分享> > HDU6704 K-th occurrence

HDU6704 K-th occurrence

作者:互联网

 

[传送门]

 

先求出SA和height。然后找到 rank[l] 的 height 值。能成为相同子串的就是和rank[l]的lcp不小于 $len$ 的。二分出左右端点之后,主席树求第k小即可。

#include <bits/stdc++.h>

const int N = 1e5 + 7;
char s[N];
int n, q;

namespace SA {
    int sa[N], rk[N], fir[N], sec[N], c[N], height[N];
    int mn[N][20], lg[N];
    void build(int len, int num = 122) {
        register int i, j, k;
        for (i = 1; i <= num; i++) c[i] = 0;
        for (i = 1; i <= len; i++) ++c[fir[i] = s[i]];
        for (i = 1; i <= num; i++) c[i] += c[i - 1];
        for (i = len; i >= 1; i--) sa[c[fir[i]]--] = i;
        for (k = 1; k <= len; k <<= 1) {
            int cnt = 0;
            for (i = len - k + 1; i <= len; i++) sec[++cnt] = i;
            for (i = 1; i <= len; i++) if (sa[i] > k) sec[++cnt] = sa[i] - k;
            for (i = 1; i <= num; i++) c[i] = 0;
            for (i = 1; i <= len; i++) ++c[fir[i]];
            for (i = 1; i <= num; i++) c[i] += c[i - 1];
            for (i = len; i >= 1; i--) sa[c[fir[sec[i]]]--] = sec[i], sec[i] = 0;
            std::swap(fir, sec);
            fir[sa[1]] = 1; cnt = 1;
            for (i = 2; i <= len; i++)
                fir[sa[i]] = (sec[sa[i]] == sec[sa[i - 1]] && sec[sa[i] + k] == sec[sa[i - 1] + k]) ? cnt : ++cnt;
            if (cnt == len) break;
            num = cnt;        
        }
        k = 0;
        for (i = 1; i <= len; i++) rk[sa[i]] = i;
        for (i = 1; i <= len; i++) {
            if (rk[i] == 1) continue;
            if (k) k--;
            j = sa[rk[i] - 1];
            while (j + k <= len && i + k <= len && s[i + k] == s[j + k]) k++;
            height[rk[i]] = k;
        }
    }

    inline int MIN(int a, int b) {
        return height[a] < height[b] ? a : b;
    }

    void init_RMQ(int n) {
        for (int i = 1, j = 0; i <= n; i++)
            lg[i] = (1 << (j + 1)) == i ? ++j : j;
        for (int i = 1; i <= n; i++) 
            mn[i][0] = i;
        for (int j = 1; j < 20; j++)
            for (int i = 1; i + (1 << j) - 1 <= n; i++)
                mn[i][j] = MIN(mn[i][j - 1], mn[i + (1 << (j - 1))][j - 1]);
    }

    int RMQ(int a, int b) {
        int log = lg[b - a + 1];
        b -= (1 << log) - 1;
        return MIN(mn[a][log], mn[b][log]);
    }

    int LCP(int i, int j) {
        i = rk[i], j = rk[j];
        if (i > j) std::swap(i, j);
        return height[RMQ(i + 1, j)];
    }
}

int root[N];

struct Seg {
    struct Tree {
        int lp, rp, sum;
    } tree[N * 20];
    int tol;
    inline void clear() {
        tol = 0;
        memset(tree, 0, sizeof(tree));
    }
    void update(int &p, int q, int l, int r, int pos) {
        tree[p = ++tol] = tree[q];
        tree[p].sum++;
        if (l == r) return;
        int mid = l + r >> 1;
        if (pos <= mid) update(tree[p].lp, tree[q].lp, l, mid, pos);
        else update(tree[p].rp, tree[q].rp, mid + 1, r, pos);
    }
    int query(int p, int q, int l, int r, int k) {
        if (l == r) return l;
        int mid = l + r >> 1;
        int sum = tree[tree[p].lp].sum - tree[tree[q].lp].sum;
        if (sum >= k) return query(tree[p].lp, tree[q].lp, l, mid, k);
        return query(tree[p].rp, tree[q].rp, mid + 1, r, k - sum);
    }
} seg;

int solve(int x, int y, int k) {
    int len = y - x + 1;
    int L = SA::rk[x];
    if (SA::height[L] >= len) {
        int l = 1, r = L;
        while (l <= r) {
            int mid = l + r >> 1;
            if (SA::LCP(SA::sa[mid], x) >= len) L = mid, r = mid - 1;
            else l = mid + 1;
        }
    }
    int R = SA::rk[x];
    if (SA::height[SA::rk[x] + 1] >= len) {
        int l = SA::rk[x] + 1, r = n;
        while (l <= r) {
            int mid = l + r >> 1;
            if (SA::LCP(x, SA::sa[mid]) >= len) R = mid, l = mid + 1;
            else r = mid - 1;
        }
    }
    //printf("%d %d\n", L, R);
    if (k > seg.tree[root[R]].sum - seg.tree[root[L - 1]].sum) return -1;
    return seg.query(root[R], root[L - 1], 1, n, k);
}

int main() {
    freopen("in.txt", "r", stdin);
    int T;
    scanf("%d", &T);
    while (T--) {
        scanf("%d%d", &n, &q);
        scanf("%s", s + 1);
        SA::build(n);
        SA::init_RMQ(n);
        seg.clear();
        for (int i = 1; i <= n; i++)
            seg.update(root[i], root[i - 1], 1, n, SA::sa[i]);
        while (q--) {
            int l, r, k;
            scanf("%d%d%d", &l, &r, &k);
            printf("%d\n", solve(l, r, k));
        }
    }
    return 0;
}
View Code

 

标签:occurrence,int,sum,HDU6704,tree,mid,len,th,SA
来源: https://www.cnblogs.com/Mrzdtz220/p/11700354.html