zoukankan      html  css  js  c++  java
  • 「luogu4096」[HE_TJOI2016] 字符串

    「luogu4096」[HE_TJOI2016] 字符串

    题目链接

    这是一道偏综合的题目(SA+主席树)。

    先后缀排序并求出 (height) 数组的区间最小值(st表);
    (sa) 当做权值建主席树;
    二分答案 (len)
    二分找到包含 (rank_c) 的最大的 (rank) 区间,使得该区间的 (height) 最小值不小于 (len),设该区间的左右端点为 (p1,p2)
    在主席树中查询 (p1)(p2) 两个历史版本之间有没有权值在 (a) ~ ((b - len + 1)),以此判断 (len) 是否可行。

    代码如下(记得开(O2)):

    // luogu-judger-enable-o2
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    int in() {
        int x = 0; char c = getchar(); bool f = 0;
        while (c < '0' || c > '9')
            f |= c == '-' , c = getchar();
        while (c >= '0' && c <= '9')
            x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
        return f ? -x : x;
    }
    
    const int N = 1e5 + 5;
    
    char s[N];
    int n, m, q, sa[N], rnk[N], tp[N << 1], hei[N], buk[N];
    int bi[N], lg[N], st_min[19][N];
    
    //Get suffix array begin
    void Tsort() {
        std::fill(buk + 1, buk + 1 + m, 0);
        for (int i = 1; i <= n; ++i)
            ++buk[rnk[i]];
        for (int i = 1; i <= m; ++i)
            buk[i] += buk[i - 1];
        for (int i = n; i; --i)
            sa[buk[rnk[tp[i]]]--] = tp[i];
    }
    
    void Ssort() {
        m = 256;
        for (int i = 1; i <= n; ++i)
            tp[i] = i, rnk[i] = s[i];
        Tsort();
        for (int w = 1, p = 0; p < n; w <<= 1, m = p) {
            p = 0;
            for (int i = n - w + 1; i <= n; ++i)
                tp[++p] = i;
            for (int i = 1; i <= n; ++i)
                if (sa[i] > w)
                    tp[++p] = sa[i] - w;
            Tsort();
            std::copy(rnk + 1, rnk + 1 + n, tp + 1);
            rnk[sa[1]] = p = 1;
            for (int i = 2; i <= n; ++i)
                rnk[sa[i]] = tp[sa[i]] == tp[sa[i - 1]] && tp[sa[i] + w] == tp[sa[i - 1] + w] ? p : ++p;
        }
    
        int k = 0;
        for (int i = 1, j; i <= n; ++i) {
            if (rnk[i] == 1)
                continue;
            if (k) --k;
            j = sa[rnk[i] - 1];
            while (i + k <= n && j + k <= n && s[i + k] == s[j + k])
                ++k;
            hei[rnk[i]] = st_min[0][rnk[i]] = k;
        }
    }
    //Get suffix array end 
    
    //persistable segment tree begin
    struct persistable_segment_tree {
    #define lson tl, mid, c[pre][0], c[p][0]
    #define rson mid + 1, tr, c[pre][1], c[p][1]
        int tot;
        int t[N * 20], c[N * 20][2], rt[N];
        void modify(int pos, int tl, int tr, int pre, int &p) {
            p = ++tot;
            t[p] = t[pre] + 1;
            if (tl == tr)
                return ;
            c[p][0] = c[pre][0], c[p][1] = c[pre][1];
            int mid = (tl + tr) >> 1;
            if (mid >= pos)
                modify(pos, lson);
            else
                modify(pos, rson);
        }
        bool query(int l, int r, int tl, int tr, int pre, int p) {
            if (l <= tl && tr <= r) {
                return t[p] - t[pre] > 0;
            }
            int mid = (tl + tr) >> 1;
            if (mid < l)
                return query(l, r, rson);
            if (mid >= r)
                return query(l, r, lson);
            else
                return query(l, r, lson) | query(l, r, rson);
        }
    #undef lson
    #undef rson
    } T;
    //persistable segment tree end
    
    //prepare begin (st_min, tree)
    void prep() {
        bi[0] = 1;
        for (int i = 1; i < 17; ++i)
            bi[i] = bi[i - 1] << 1;
        for (int i = 2; i <= n; ++i)
            lg[i] = lg[i >> 1] + 1;
        for (int k = 1; k < 17; ++k)
            for (int i = 1; i + bi[k] - 1 <= n; ++i)
                st_min[k][i] = std::min(st_min[k - 1][i], st_min[k - 1][i + bi[k - 1]]);
        for (int i = 1; i <= n; ++i) {
            T.modify(sa[i], 1, n, T.rt[i - 1], T.rt[i]);
        }
    }
    int query_lcp(int l, int r) {
        if (l > r)
            return 0x3f3f3f3f;
        int k = lg[r - l + 1];
        return std::min(st_min[k][l], st_min[k][r - bi[k] + 1]);
    }
    //prepare end (st_min, tree)
    
    //binary search begin
    bool chk(int x, int y, int p, int lim) {
        int l = 1, r = p, mid, p1, p2;
        while (l < r) {
            mid = (l + r) >> 1;
            if (query_lcp(mid + 1, p) < lim)
                l = mid + 1;
            else
                r = mid;
        }
        p1 = l;
        l = p, r = n;
        while (l < r) {
            mid = (l + r + 1) >> 1;
            if (query_lcp(p + 1, mid) >= lim)
                l = mid;
            else
                r = mid - 1;
        }
        p2 = l;
        return T.query(x, y, 1, n, T.rt[p1 - 1], T.rt[p2]);
    }
    //binary search end 
    
    int main() {
        n = in(), q = in();
        scanf(" %s", s + 1);
        Ssort(), prep();
        int a, b, c, d, l, r, mid;
        while (q--) {
            a = in(), b = in(), c = in(), d = in();
            l = 0, r = std::min(b - a + 1, d - c + 1);
            while (l < r) {
                mid = (l + r + 1) >> 1;
                if (chk(a, b - mid + 1, rnk[c], mid))
                    l = mid;
                else
                    r = mid - 1;
            }
            printf("%d
    ", l);
        }
        return 0;
    }
    
  • 相关阅读:
    Qt 打印机支持模块
    手动启动jenkins
    Ubuntu下安装Apache2, php5 mysql
    Ubuntu 使用apt-get时提示错误:无法获得锁 /var/lib/dpkg/lock
    scp 在不同机器上传文件
    python 正则表达式 贪婪模式的简介和匹配时的几种模式
    python指定pypi的源地址 镜像地址
    python三元运算符
    python导入上级目录中的模块
    linux下使用vim替换文件中的^M换行符
  • 原文地址:https://www.cnblogs.com/15owzLy1-yiylcy/p/10938045.html
Copyright © 2011-2022 走看看