P8571 题解

既然字符串的总长一定,不妨对于每个询问中的 \(s_k\) 的长度根号分治,假定分治阈值为 \(B\)。下面令 \(L\) 为所有串长度总和。

对于长度大于 \(B\) 的字符串,这样的不同字符串至多有 \(\frac{L}{B}\) 个,考虑对于每个字符串建立 AC 自动机,然后暴力匹配出其他字符串的出现次数,并 \(O(n)\) 建立一个线段树来回答询问,这一部分复杂度是 \(O(\frac{L^2}{B} + q \log n)\) 的。

对于长度小于等于 \(B\) 的字符串,它的前缀至多有 \(B\) 个,映射到 AC 自动机上 \(B\) 个点,我们要查询这些点在失配树上到祖先的路径上处于区间 \([l,r]\) 内的终止节点出现最多的终止节点出现次数。

不妨假定这个终止节点是点 \(x\),根据 AC 自动机的性质,其产生贡献的前缀节点在失配树上 \(x\) 的子树内,这提示我们,无论如何产生贡献的前缀节点都在某一个子树内。并且这个子树内的前缀节点也都产生了贡献。

所以考虑建出所有前缀节点的虚树,那么我们枚举虚树上的节点,问题转变为判断这个节点是否会产生贡献。

显然这是一个二维数点问题,不妨对 \(r\) 做一遍扫描线,问题转变为点修链查最大值,再将其转变为子树修改单点查最大值,考虑用一个 \(O(\sqrt L)\) 修改 \(O(1)\) 查询的分块维护,由于虚树大小是 \(O(B)\) 的,所以这部分复杂度是 \(O(L \sqrt L + L \times B + L \log L)\)

显然当 \(B = \sqrt L\) 的时候取到最小值 \(O(L \sqrt L + q \log n + L \log L)\) 此时空间也是 \(O(L)\) 的。

注意时间空间常数问题。

要是你被卡常了可以尝试一个经典的 trick,将遍历树的过程用在树的 dfs 序上扫描完成。

#include <bits/stdc++.h>
#define query(x) (max(a[x],tag[bp[x]]))
using namespace std;
const int maxn = 1e5 + 5;
const int warma = 707;
string s[maxn];
int Len[maxn];
struct Query {
    Query(int L, int R, int ID) {
        l = L, r = R, id = ID;
    }
    int l, r, id;
};
int n, q;
vector<Query> Q[maxn];
int answer[maxn];
vector<int> Vtree;//虚树
int L[maxn * 5], R[maxn * 5], Node[maxn * 5];
int bp[maxn * 5];
int son[maxn * 5][26], fail[maxn * 5], rt, tot, dfncnt;
int sz[maxn * 5], Hson[maxn * 5], top[maxn * 5], dep[maxn * 5];
vector< pair<int, int>> w[maxn];
vector<int> edge[maxn * 5];
vector<int> fa[maxn];
vector<int> road[maxn * 5]; //虚树上的节点
int endpos[maxn * 5];
int found[maxn];
inline void insert(int pos) {
    int len = s[pos].size(), now = rt;

    for (register int i = 0; i < len; i = -~i) {
        if (son[now][s[pos][i] - 'a'] == 0)
            son[now][s[pos][i] - 'a'] = ++tot;

        now = son[now][s[pos][i] - 'a'];
        fa[pos].push_back(now);
    }

    if (endpos[now] == 0)
        found[pos] = endpos[now] = pos;
    else
        found[pos] = endpos[now];
}
inline void build() {
    queue<int> q;

    for (register int i = 0; i < 26; i = -~i)
        if (son[rt][i])
            fail[son[rt][i]] = rt, q.push(son[rt][i]);

    while (q.size() > 0) {
        int u = q.front();
        q.pop();

        for (register int i = 0; i < 26; i = -~i) {
            if (son[u][i]) {
                fail[son[u][i]] = son[fail[u]][i];
                q.push(son[u][i]);
            } else
                son[u][i] = son[fail[u]][i];
        }
    }

    for (register int i = 1; i <= tot; i = -~i) {
        edge[fail[i]].push_back(i);
    }
}
inline void dfs(int u) {
    L[u] = ++dfncnt, Node[dfncnt] = u, sz[u] = 1;

    for (register int i = 0; i < edge[u].size(); i = -~i) {
        dep[edge[u][i]] = dep[u] + 1;
        dfs(edge[u][i]);
        sz[u] += sz[edge[u][i]];

        if (Hson[u] == -1 || sz[edge[u][i]] > sz[Hson[u]])
            Hson[u] = edge[u][i];
    }

    R[u] = dfncnt;
}
inline void HLD(int u, int tp) {
    top[u] = tp;

    for (register int i = 0; i < edge[u].size(); i = -~i) {
        if (edge[u][i] != Hson[u])
            HLD(edge[u][i], edge[u][i]);
    }

    if (Hson[u] != -1)
        HLD(Hson[u], tp);
}
inline int LCA(int u, int v) {
    while (top[u] != top[v]) {
        if (dep[top[u]] < dep[top[v]])
            swap(u, v);

        u = fail[top[u]];
    }

    if (dep[u] < dep[v])
        swap(u, v);

    return v;
}
int tag[maxn], a[maxn * 5];
inline void cover(int l, int r, int v) {
    int bl = bp[l], br = bp[r];

    if (bl == br) {
        for (register int i = l; i <= r; i = -~i)
            a[i] = v;

        return ;
    }

    for (register int i = bl + 1; i < br; i = -~i)
        tag[i] = v;

    for (register int i = l; i <= bl * warma; i = -~i)
        a[i] = v;

    for (register int i = (br - 1) * warma + 1; i <= r; i = -~i)
        a[i] = v;
}
struct ASK {
    int l, k, id;
    ASK(int L, int K, int ID) {
        l = L, k = K, id = ID;
    }
};
int tr[maxn << 2];
inline void build(int cur, int lt, int rt) {
    if (lt == rt) {
        tr[cur] = sz[fa[lt].back()];
        return ;
    }

    int mid = (lt + rt) >> 1;
    build(cur << 1, lt, mid);
    build(cur << 1 | 1, mid + 1, rt);
    tr[cur] = max(tr[cur << 1], tr[cur << 1 | 1]);
}
inline int query_mx(int cur, int l, int r, int lt, int rt) {
    if (l <= lt && rt <= r)
        return tr[cur];

    if (r < lt || l > rt)
        return 0;

    int mid = (lt + rt) >> 1;
    return max(query_mx(cur << 1, l, r, lt, mid), query_mx(cur << 1 | 1, l, r, mid + 1, rt));
}
inline bool cmp(int A, int B) {
    return L[A] < L[B];
}
vector<ASK> ask[maxn];
inline void V_build(int u) {
    for (register int i = 0; i < road[u].size(); i = -~i) {
        int v = road[u][i];
        V_build(v);
        sz[u] += sz[v];
    }
}
inline bool cmp1(pair<int, int> A, pair<int, int> B) {
    return A.second > B.second;
}
inline string sread() {
    string ans;
    char ch = getchar();

    while (ch < 'a' || ch > 'z')
        ch = getchar();

    while (ch >= 'a' && ch <= 'z')
        ans += ch, ch = getchar();

    return ans;
}
inline int read() {
    bool flag = false;
    int x = 0;
    char ch = getchar();

    while (ch < '0' || ch > '9') {
        if (ch == '-')
            flag = true;

        ch = getchar();
    }

    while (ch >= '0' && ch <= '9') {
        x = (x << 1) + (x << 3) + ch - '0';
        ch = getchar();
    }

    return flag ? -x : x;
}
void write(int x) {
    if (x < 0) {
        putchar('-');
        x = -x;
    }

    if (x > 9)
        write(x / 10);

    putchar(x % 10 ^ 48);
}
int flag[maxn];
int B;
set<int> S;
int root;
int main() {
    memset(Hson, -1, sizeof(Hson));
    n = read();
    q = read();

    for (register int i = 1; i <= n; i = -~i)
        s[i] = sread(), Len[i] = s[i].size(), B += Len[i];

    B = sqrt(B) * 1.4;

    for (register int i = 1; i <= n; i = -~i)
        insert(i);

    for (register int i = 1; i <= q; i = -~i) {
        int l, r, k;
        l = read();
        r = read();
        k = read();

        if (Len[k] <= B) {
            flag[k] = 1;
            ask[r].push_back(ASK(l, k, i));
        } else {
            Q[found[k]].push_back(Query(l, r, i));
        }
    }

    build();
    dfs(rt);
    HLD(rt, rt);

    for (register int i = 1; i <= dfncnt; i++)
        bp[i] = (i - 1) / warma + 1;

    for (register int i = 0; i <= tot; i++)
        sz[i] = 0;

    for (register int i = 1; i <= n; i = -~i) {
        if (flag[i] == 0)
            continue;

        S.clear();
        Vtree.clear();
        root = -1;

        for (register int j = 0; j < fa[i].size(); j = -~j)
            Vtree.push_back(fa[i][j]), S.insert(fa[i][j]), sz[fa[i][j]]++;

        sort(Vtree.begin(), Vtree.end(), cmp);

        for (register int j = 0; j < Vtree.size() - 1; j = -~j) {
            int u = LCA(Vtree[j], Vtree[j + 1]);
            S.insert(u);
        }

        Vtree.clear();

        for (set<int>::iterator i = S.begin(); i != S.end(); ++i) {
            Vtree.push_back((*i));

            if (root == -1 || dep[(*i)] < dep[root])
                root = (*i);
        }

        sort(Vtree.begin(), Vtree.end(), cmp);

        for (register int j = 0; j < Vtree.size() - 1; j = -~j) {
            int u = LCA(Vtree[j], Vtree[j + 1]);
            road[u].push_back(Vtree[j + 1]);
        }

        V_build(root);

        for (register int j = 0; j < Vtree.size(); j = -~j)
            w[i].push_back(make_pair(Vtree[j], sz[Vtree[j]]));

        sort(w[i].begin(), w[i].end(), cmp1);

        for (register int j = 0; j < Vtree.size(); j = -~j) {
            sz[Vtree[j]] = 0;
            road[Vtree[j]].clear();
        }
    }

    for (register int i = 1; i <= n; i = -~i) {
        cover(L[fa[i].back()], R[fa[i].back()], i);

        for (register int j = 0; j < ask[i].size(); j = -~j) {
            for (register int k = 0; k < w[ask[i][j].k].size(); k = -~k) {
                if (query(L[w[ask[i][j].k][k].first]) >= ask[i][j].l) {
                    answer[ask[i][j].id] = max(answer[ask[i][j].id], w[ask[i][j].k][k].second);
                    break;
                }
            }
        }
    }

    for (register int i = 1; i <= n; i = -~i) {
        if (Q[i].size() > 0) {
            for (register int j = 0; j <= tot; j = -~j)
                sz[j] = 0;

            for (register int j = 0; j < fa[i].size(); j = -~j) {
                ++sz[fa[i][j]];
            }

            for (int u = dfncnt; u >= 1; --u) {
                if (Node[u] != rt)
                    sz[fail[Node[u]]] += sz[Node[u]];
            }

            build(1, 1, n);

            for (register int j = 0; j < Q[i].size(); j = -~j) {
                answer[Q[i][j].id] = query_mx(1, Q[i][j].l, Q[i][j].r, 1, n);
            }
        }
    }

    for (register int i = 1; i <= q; i = -~i)
        write(answer[i]), putchar('\n');

    return 0;
}
/*
6 1
a
aaa
dedicatus
misaka
mikoto
mi
1 2 2
*/
posted @ 2024-01-31 00:00  ChiFAN鸭  阅读(5)  评论(0编辑  收藏  举报