• [2019CCPC网络赛][hdu6704]K-th occurrence(后缀数组&&主席树)


    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6704

    题意为查询子串s[l...r]第k次出现的位置。

    写完博客后5分钟的更新


    写完博客才发现这份代码和杭电的代码查重了....

    为什么会变成这样呢?是我先交的,明明是我先交的…


    激动!!第一次网络赛做出这种(板子)题。

    首先求一下后缀数组的Height,我们知道Height数组表示两个排名相邻的后缀的最长公共前缀,则Height数组的区间最小值即为区间排名相邻的后缀的最长公共前缀。

    我们想知道那些后缀包含了所查询的区间s[l...r]这样的前缀,则先找到s[l...n]这个后缀的排名,然后在包含这个排名的Height数组中找到最长的区间,且该区间最小值要大于等于r-l+1。即该区间内的后缀的最长公共前缀包含s[l...r]。

    找这个最长的区间就可以分别二分左右端点,判断用ST表预处理Height数组,然后O(1)查询即可。

    然后我们的任务就是在这个区间内找到第k小的位置。这个问题就可以对后缀数组的排名建主席树。然后查询即可。

    #include<bits/stdc++.h>
    #define lson l,mid,i<<1
    #define rson mid+1,r,i<<1|1
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const int maxn = 2e5 + 110;
    int sa[maxn], tax[maxn], rak[maxn], tp[maxn], Height[maxn], lg[maxn];
    int dp[maxn][20];
    int root[maxn], ls[maxn * 40], rs[maxn * 40], val[maxn * 40], cnt;
    char s[maxn];
    void Qsort(int n, int m) {
        for (int i = 0; i < m; i++) tax[i] = 0;
        for (int i = 0; i < n; i++) tax[rak[i]]++;
        for (int i = 0; i < m; i++) tax[i] += tax[i - 1];
        for (int i = n - 1; i >= 0; i--) sa[--tax[rak[tp[i]]]] = tp[i];
    }
    void suffix(int n, int m) {//n为原串长度+1,m为原串的种类
        for (int i = 0; i < n; i++)
            rak[i] = s[i], tp[i] = i;
        Qsort(n, m);
        //debug();
        for (int k = 1; k <= n; k <<= 1) {
            int p = 0;
            for (int i = n - k; i < n; i++) tp[p++] = i;
            for (int i = 0; i < n; i++) if (sa[i] >= k) tp[p++] = sa[i] - k;
            Qsort(n, m);
            swap(rak, tp);
            p = 1;
            rak[sa[0]] = 0;
            for (int i = 1; i < n; i++)
                rak[sa[i]] = (tp[sa[i - 1]] == tp[sa[i]] && tp[sa[i - 1] + k] == tp[sa[i] + k]) ? p - 1 : p++;
            if (p >= n)
                break;
            m = p;
        }
    }
    void getH(int n) {
        int j, k = 0;
        for (int i = 0; i <= n; i++)
            rak[sa[i]] = i;
        for (int i = 0; i < n; i++) {
            if (k)k--;
            j = sa[rak[i] - 1];
            while (s[i + k] == s[j + k])
                k++;
            Height[rak[i]] = k;
        }
    }
    void RMQ(int n) {
        for (int i = 1; i <= n; i++)
            dp[i][0] = Height[i];
        for (int j = 1; (1 << j) <= 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]);
        }
        lg[0] = -1;
        for (int i = 1; i <= n; i++) {
            if ((i&(i - 1)) == 0)
                lg[i] = lg[i - 1] + 1;
            else
                lg[i] = lg[i - 1];
        }
    }
    int queryR(int l, int r) {
        int k = lg[r - l + 1];
        return min(dp[l][k], dp[r - (1 << k) + 1][k]);
    }
    void build(int l, int r, int &i) {
        i = ++cnt;
        val[i] = 0;
        if (l == r)
            return;
        int mid = l + r >> 1;
        build(l, mid, ls[i]);
        build(mid + 1, r, rs[i]);
    }
    void update(int k, int l, int r, int &i) {
        ls[++cnt] = ls[i], rs[cnt] = rs[i], val[cnt] = val[i] + 1;
        i = cnt;
        if (l == r)
            return;
        int mid = l + r >> 1;
        if (k <= mid)
            update(k, l, mid, ls[i]);
        else
            update(k, mid + 1, r, rs[i]);
    }
    int query(int u, int v, int k, int l, int r) {
        if (l == r)
            return l;
        int x = val[ls[v]] - val[ls[u]];
        int mid = l + r >> 1;
        if (x >= k)
            return query(ls[u], ls[v], k, l, mid);
        else
            return query(rs[u], rs[v], k - x, mid + 1, r);
    }
    int main() {
        int t;
        scanf("%d", &t);
        while (t--) {
            int n, q, cnt = 0;
            scanf("%d%d", &n, &q);
            scanf("%s", s);
            suffix(n + 1, 256);
            getH(n);
            for (int i = 1; i <= n; i++)
                ++sa[i];
            for (int i = n; i >= 1; i--)
                rak[i] = rak[i - 1];
            RMQ(n);
            build(1, n, root[0]);
            for (int i = 1; i <= n; i++) {
                root[i] = root[i - 1];
                update(sa[i], 1, n, root[i]);
            }
            //for (int i = 1; i <= n; i++)
            //    printf("%d%c", sa[i], i == n ? '
    ' : ' ');
            //for (int i = 1; i <= n; i++)
            //    printf("%d%c", rak[i], i == n ? '
    ' : ' ');
            //for (int i = 1; i <= n; i++)
            //    printf("%d%c", Height[i], i == n ? '
    ' : ' ');
            while (q--) {
                int l, r, k, len;
                scanf("%d%d%d", &l, &r, &k);
                len = r - l + 1;
                int x = rak[l], y = rak[l];
                int L = x + 1, R = n;
                while (L <= R) {
                    int mid = L + R >> 1;
                    if (queryR(L, mid) >= len)
                        y = mid, L = mid + 1;
                    else
                        R = mid - 1;
                }
                L = 2, R = x;
                while (L <= R) {
                    int mid = L + R >> 1;
                    if (queryR(mid, R) >= len)
                        x = mid - 1, R = mid - 1;
                    else
                        L = mid + 1;
                }
                //cout << x << " " << y << endl;
                if (y - x + 1 < k)
                    printf("-1
    ");
                else
                    printf("%d
    ", query(root[x - 1], root[y], k, 1, n));
            }
        }
    }
  • 相关阅读:
    Jmeter 将正则表达式提取的参数传给全局(跨线程组使用变量)
    pod的状态分析
    前端 -- html介绍和head标签
    Python ----- 线程和进程
    网络编程 ------ 基础
    面向对象相关操作
    面向对象 --- 进阶篇
    python --- 面向对象
    python的模块和包的详细说明
    常用模块------时间模块 , random模块 ,os模块 , sys模块
  • 原文地址:https://www.cnblogs.com/sainsist/p/11409152.html
Copyright © 2020-2023  润新知