做两道sam+线段树合并的题

mark。
cf666e,cf700e

进度1/2
码量大的吐血,思路顺了翘起来很爽,一卡直接被巨量的代码搞得瞬间暴死。

#include <bits/stdc++.h>

using namespace std;
typedef pair<int, int> pii;
typedef long long ll;

const int maxn = 6e5 + 5;

int n, q;
string s, pp;

pii cmp(pii a, pii b) {
    if (a.second == b.second) {
        if (a.first < b.first) {
            return a;
        }
        return b;
    }
    if (a.second < b.second) {
        return b;
    }
    return a;
}

struct Sam {
    int next[maxn << 1][26];
    int link[maxn << 1], step[maxn << 1];
    int endpos[maxn << 1], id[maxn];
    int a[maxn], b[maxn << 1];
    int sz, last, root;

    int ls[maxn * 50], rs[maxn * 50], tot;
    pii tree[maxn * 50];

    int rmq[maxn << 1][21];

    void update(int &i, int l, int r, int pos) {
        if (!i) {
            i = ++tot;
        }
        if (l == r) {
            tree[i].first = l;
            ++tree[i].second;
            return;
        }
        int mid = (l + r) >> 1;
        if (pos <= mid) {
            update(ls[i], l, mid, pos);
        } else {
            update(rs[i], mid + 1, r, pos);
        }
        tree[i] = cmp(tree[ls[i]], tree[rs[i]]);
    }

    int merge(int x, int y, int l, int r) {
        if (!x || !y) {
            return x + y;
        }
        int z = ++tot, mid = (l + r) >> 1;
//        tree[z] = cmp(tree[x], tree[y]);
        if (l == r) {
            tree[z] = {l, tree[x].second + tree[y].second};
            return z;
        }
        ls[z] = merge(ls[x], ls[y], l, mid);
        rs[z] = merge(rs[x], rs[y], mid + 1, r);
        tree[z] = cmp(tree[ls[z]], tree[rs[z]]);
        return z;
    }

    pii query(int i, int l, int r, int L, int R) {
        if (l >= L && r <= R) {
            return tree[i];
        }
        int mid = (l + r) >> 1;
        pii ans = {0, 0};
        if (L <= mid) {
            ans = cmp(ans, query(ls[i], l, mid, L, R));
        }
        if (R > mid) {
            ans = cmp(ans, query(rs[i], mid + 1, r, L, R));
        }
        return ans;
    }

    void init() {
        //如多次建立自动机,加入memset操作
        root = sz = last = 1;
    }

    void add(int c) {
        if (next[last][c] && step[last] + 1 == step[next[last][c]]) {
            last = next[last][c];
            return;
        }

        int p = last;
        int np = ++sz;
        last = np;

        step[np] = step[p] + 1;
        while (!next[p][c] && p) {
            next[p][c] = np;
            p = link[p];
        }

        if (p == 0) {
            link[np] = root;
        } else {
            int q = next[p][c];
            if (step[p] + 1 == step[q]) {
                link[np] = q;
            } else {
                int nq = ++sz;
                memcpy(next[nq], next[q], sizeof(next[q]));
                step[nq] = step[p] + 1;
                link[nq] = link[q];
                link[q] = link[np] = nq;
                while (next[p][c] == q && p) {
                    next[p][c] = nq;
                    p = link[p];
                }
            }
        }
    }

    void build() {
        init();
        for (int i = 0; i < pp.length(); ++i) {
            add(pp[i] - 'a');
            id[i] = last;
        }
        for (int i = 1; i <= n; ++i) {
            cin >> s;
            last = root;
            for (int j = 0; j < s.length(); ++j) {
                add(s[j] - 'a');
                update(endpos[last], 1, n, i);
            }
        }
        for (int i = root; i <= sz; ++i) {
            rmq[i][0] = link[i];
        }
        for (int j = 1; j <= 20; ++j) {
            for (int i = root; i <= sz; ++i) {
                rmq[i][j] = rmq[rmq[i][j - 1]][j - 1];
            }
        }
        for (int i = 1; i <= sz; i++) {
            a[step[i]]++;
        }
        for (int i = 1; i <= sz; i++) {
            a[i] += a[i - 1];
        }
        for (int i = 1; i <= sz; i++) {
            b[a[step[i]]--] = i;
        }
        for (int i = sz; i > root; --i) {
            int e = b[i];
            endpos[link[e]] = merge(endpos[link[e]], endpos[e], 1, n);
        }
    }

    void solve(int l, int r, int pl, int pr) {
        int p = id[pr];
        for (int i = 20; ~i; --i) {
            if (step[rmq[p][i]] >= pr - pl + 1) {
                p = rmq[p][i];
            }
        }
        pii ans = query(endpos[p], 1, n, l, r);
        if (ans.first == 0) {
            cout << l << " " << 0 << '\n';
            return;
        }
        cout << ans.first << ' ' << ans.second << '\n';
    }
} sam;


int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> pp >> n;
    sam.build();
    cin >> q;
    int l, r, pl, pr;
    while (q--) {
        cin >> l >> r >> pl >> pr;
        sam.solve(l, r, pl - 1, pr - 1);
    }
    return 0;
}

mark2

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

const int maxn = 2e5 + 5;

int n;
string s;

struct Sam {
    int next[maxn << 1][26];
    int link[maxn << 1], step[maxn << 1];
    int endpos[maxn << 1], pos[maxn << 1];
    int a[maxn], b[maxn << 1];
    int subseq[maxn << 1], dp[maxn << 1];
    int sz, last, root;

    int ls[maxn * 50], rs[maxn * 50], tot;

    void update(int &i, int l, int r, int pos) {
        if (!i) {
            i = ++tot;
        }
        if (l == r) {
            return;
        }
        int mid = (l + r) >> 1;
        if (pos <= mid) {
            update(ls[i], l, mid, pos);
        } else {
            update(rs[i], mid + 1, r, pos);
        }
    }

    int merge(int x, int y) {
        if (!x || !y) {
            return x + y;
        }
        int z = ++tot;
        ls[z] = merge(ls[x], ls[y]);
        rs[z] = merge(rs[x], rs[y]);
        return z;
    }

    int query(int i, int l, int r, int L, int R) {
        if (!i) {
            return 0;
        }
        if (l >= L && r <= R) {
            return 1;
        }
        int mid = (l + r) >> 1;
        int ans = 0;
        if (L <= mid) {
            ans |= query(ls[i], l, mid, L, R);
        }
        if (R > mid) {
            ans |= query(rs[i], mid + 1, r, L, R);
        }
        return ans;
    }

    void init() {
        //如多次建立自动机,加入memset操作
        root = sz = last = 1;
    }

    void add(int c, int id) {
        int p = last;
        int np = ++sz;
        last = np;

        pos[np] = id;
        update(endpos[np], 1, n, id);
        step[np] = step[p] + 1;
        while (!next[p][c] && p) {
            next[p][c] = np;
            p = link[p];
        }

        if (p == 0) {
            link[np] = root;
        } else {
            int q = next[p][c];
            if (step[p] + 1 == step[q]) {
                link[np] = q;
            } else {
                int nq = ++sz;
                memcpy(next[nq], next[q], sizeof(next[q]));
                step[nq] = step[p] + 1;
                link[nq] = link[q];
                pos[nq] = pos[q];
                link[q] = link[np] = nq;
                while (next[p][c] == q && p) {
                    next[p][c] = nq;
                    p = link[p];
                }
            }
        }
    }

    void build() {
        init();
        for (int i = 0; i < s.length(); i++) {
            add(s[i] - 'a', i + 1);
        }
        for (int i = 1; i <= sz; i++) {
            a[step[i]]++;
        }
        for (int i = 1; i <= step[last]; i++) {
            a[i] += a[i - 1];
        }
        for (int i = 1; i <= sz; i++) {
            b[a[step[i]]--] = i;
        }
        for (int i = sz; i >= root; --i) {
            int e = b[i];
            endpos[link[e]] = merge(endpos[link[e]], endpos[e]);
        }
    }

    void solve() {
        int ans = 1;
        for (int i = root; i <= sz; ++i) {
            int e = b[i];
            if (link[e] == root) {
                dp[e] = 1, subseq[e] = e;
            } else if (query(endpos[subseq[link[e]]], 1, n, pos[e] - step[e] + step[subseq[link[e]]], pos[e] - 1)) {
                dp[e] = dp[link[e]] + 1, subseq[e] = e;
            } else {
                dp[e] = dp[link[e]], subseq[e] = subseq[link[e]];
            }
            ans = max(ans, dp[e]);
        }
        cout << ans;
    }
} sam;


int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> n >> s;
    sam.build();
    sam.solve();
    return 0;
}
发布了156 篇原创文章 · 获赞 20 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/Cymbals/article/details/89883254