P9623 [ICPC2020 Nanjing R] Baby‘s First Suffix Array Problem

#include <bits/stdc++.h>
using namespace std;
#define P pair
#define fi first 
#define se second 
#define eb emplace_back
#define vec vector
namespace lzyqwq {
    const int N = 50005; P<int, int> arr[N];
    int n, m, lg[N], ans[N], pmn[N]; string s; vec<int> buc;
    struct SparseTable {
        int a[20][N];
        void build(int *b) {
            for (int i = 1; i <= n; ++i) a[0][i] = b[i];
            for (int i = 1; i <= lg[n]; ++i)
                for (int j = 1; j + (1 << i) - 1 <= n; ++j)
                    a[i][j] = min(a[i - 1][j], a[i - 1][j + (1 << (i - 1))]);
        }
        int Q(int l, int r) {
            int k = lg[r - l + 1]; return min(a[k][l], a[k][r - (1 << k) + 1]);
        }
    };
    struct SuffixArray {
        int sa[N], rk[N], ht[N], tmp[30]; P<P<int, int>, int> p[N]; SparseTable st;
        void work() {
            memset(tmp, 0, sizeof tmp);
            for (int i = 1; i <= n; ++i) ++tmp[s[i] - 'a' + 1];
            for (int i = 1; i <= 26; ++i) tmp[i] += tmp[i - 1];
            for (int i = 1; i <= n; ++i) rk[i] = tmp[s[i] - 'a'] + 1;
            for (int l = 1, id; l <= n; l <<= 1) {
                for (int i = 1; i <= n; ++i)
                    p[i] = {{rk[i], i + l > n ? 0 : rk[i + l]}, i};
                stable_sort(p + 1, p + n + 1); id = 0;
                for (int i = 1; i <= n; ++i) {
                    if (i == 1 || p[i].fi != p[i - 1].fi) ++id; rk[p[i].se] = id;
                }
                if (id == n) break;
            }
            for (int i = 1; i <= n; ++i) sa[rk[i]] = i, ht[i] = 0;
            for (int i = 1, j, k = 0; i <= n; ++i) {
                if (rk[i] == 1) { k = 0; continue; }
                if (k) --k; j = sa[rk[i] - 1];
                while (i + k <= n && j + k <= n && s[i + k] == s[j + k]) ++k;
                ht[rk[i]] = k;
            }
            st.build(ht);
        }
        int lcp(int x, int y) {
            if (x == y) return n - sa[x] + 1; 
            if (x > y) swap(x, y); ++x; return st.Q(x, y);
        }
    } S;
    struct ChairmanTree {
        int ls[N * 20], rs[N * 20], cnt, sum[N * 20], rt[N];
        void I() {
            for (int i = 1; i <= cnt; ++i) ls[i] = rs[i] = sum[i] = 0;
            for (int i = 1; i <= n; ++i) rt[i] = 0; cnt = 0;
        }
        void mdf(int &x, int y, int l, int r, int k, int v) {
            x = ++cnt; sum[x] = sum[y] + v; 
            if (l == r) return; int m = (l + r) >> 1;
            if (k <= m) rs[x] = rs[y], mdf(ls[x], ls[y], l, m, k, v);
            else ls[x] = ls[y], mdf(rs[x], rs[y], m + 1, r, k, v);
        }
        int qry(int x, int y, int l, int r, int ql, int qr) {
            if (ql <= l && r <= qr) return sum[x] - sum[y]; 
            int m = (l + r) >> 1, R = 0;
            if (ql <= m) R = qry(ls[x], ls[y], l, m, ql, qr);
            if (qr > m) R += qry(rs[x], rs[y], m + 1, r, ql, qr); return R;
        }
        void M(int x, int y, int k, int v) { mdf(rt[x], rt[y], 1, n, k, v); }
        int Q(int x, int y, int l, int r) { 
            if (x > y || l > r) return 0;
            return qry(rt[y], rt[x - 1], 1, n, l, r); 
        }
    } T;
    struct Qries {
        int l, r, k, id;
        Qries(int ll = 0, int rr = 0, int kk = 0, int ii = 0) {
            l = ll; r = rr; k = kk; id = ii;
        }
    }; vec<Qries> q[N];
    void init() {
        T.I(); for (int i = 1; i <= n; ++i) q[i].clear();
    }
    int count(int l, int r) {
        return upper_bound(buc.begin(), buc.end(), r) - 
               lower_bound(buc.begin(), buc.end(), l);
    }
    void cdq(int l, int r) {
        if (l == r) return; int m = (l + r) >> 1; 
        pmn[m + 1] = S.ht[m + 1]; T.I(); buc.clear();
        for (int i = m + 2; i <= r; ++i) pmn[i] = min(S.ht[i], pmn[i - 1]);
        for (int i = m + 1; i <= r; ++i)
            buc.eb(S.sa[i]), arr[i] = {S.sa[i] + pmn[i], S.sa[i]};
        stable_sort(arr + m + 1, arr + r + 1); stable_sort(buc.begin(), buc.end());
        for (int i = m + 1; i <= r; ++i) T.M(i, i - 1, arr[i].se, 1);
        for (int i = m, mn = N, ql, qr, f, mid; i >= l; --i) {
            for (auto [L, R, k, id] : q[i]) {
                ql = m + 1, qr = r, f = m, mid;
                while (ql <= qr) {
                    int mid = (ql + qr) >> 1;
                    if (arr[mid].fi <= R) f = mid, ql = mid + 1; else qr = mid - 1;
                }
                ans[id] += count(max(R - mn, k) + 1, R) - 
                           T.Q(m + 1, f, max(k, R - mn) + 1, R);
            }  
            mn = min(mn, S.ht[i]);
        }
        cdq(l, m); cdq(m + 1, r);
    }
    void work() {
        init(); cin >> n >> m >> s; s = ' ' + s; S.work();
        for (int i = 1; i <= n; ++i) T.M(i, i - 1, S.sa[i], 1);
        for (int i = 1, l, r, k; i <= m; ++i) {
            cin >> l >> r >> k; q[S.rk[k]].eb(l, r, k, i); ans[i] = 0;
            if (r != k) ans[i] = T.Q(1, S.rk[k] - 1, k + 1, r);
            if (l != k) {
                int ql = 1, qr = S.rk[k], f = 0, md;
                while (ql <= qr) {
                    md = (ql + qr) >> 1;
                    if (S.lcp(md, S.rk[k]) <= r - k) f = md, ql = md + 1; 
                    else qr = md - 1;
                }
                ans[i] += T.Q(1, f, l, k - 1);
            }
        }
        cdq(1, n); for (int i = 1; i <= m; ++i) cout << ans[i] + 1 << '\n';
    }
    void Main() {
        cin.tie(0), cout.tie(0), ios::sync_with_stdio(0);
        for (int i = 1; i < N; ++i) lg[i] = __lg(i);
        int testcases; cin >> testcases; while (testcases--) work();
    }
}
signed main(void)
{
return lzyqwq::Main(), 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值