「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;
}
原文地址:https://www.cnblogs.com/15owzLy1-yiylcy/p/10938045.html