嘘~ 正在从服务器偷取页面 . . .

CF163E e-Government 题解


CF163E e-Government 题解

题目链接:CF163E e-Government

题意

给定包含 \(k\) 个字符串的集合 \(S\),有 \(n\) 个操作,操作有三种类型:

? 开头的操作为询问操作,询问当前字符串集 \(S\) 中的每一个字符串匹配询问字符串的次数之和;

+ 开头的操作为添加操作,表示将编号为 \(i\) 的字符串加入到集合中;

- 开头的操作为删除操作,表示将编号为 \(i\) 的字符串从集合中删除。

具体格式参照样例。

注意当编号为 \(i\) 的字符串已经在集合中时,允许存在添加编号为 \(i\)​ 的字符串的操作,但此时不执行此操作;删除亦然。

数据范围

\(1\le n,k \le 10^5,~1\le \sum |S_i| \le 10^6\)

这题其实很简单啦,然后我 #define int long long 居然被卡空间了……

根据 Fail 树的性质,字符串 \(x\) 能对 \(y\) 有贡献,则 \(x\) 的结尾节点是 \(y\) 的某个节点的祖先。

也就是说,一个 \(x\) 能对(自己在 Fail 树上的)子树的所有节点产生 \(1\) 的贡献。

那么对于询问,我们只需要扫一遍询问串,即让一个指针在AC自动机上面跳,并统计这个节点上有多少贡献

诶,子树加,单点查询,这不就是树状数组板子吗!然后这题就做完了。

其实这道题就是 P2414 [NOI2011] 阿狸的打字机 的简化版。

时间复杂度 \(\mathcal{O}\left(\left(k + \sum |S_i|\right) \log \sum |S_i|\right)\)

代码:

#include <bits/stdc++.h>
using namespace std;
// #define int long long
// #define INF 0x3f3f3f3f3f3f3f3f
typedef long long ll;
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(1e6 + 15))

char s[N], live[N]; ll tr[N];
vector<int> vec[N]; queue<int> q;
int tot, sz[N], dfn[N], trie[N][26], fail[N], ed[N];
int lowbit(int x) { return x & (-x); }
void add(int x, int v) { for(int i = x; i <= tot + 1; i += lowbit(i)) tr[i] += v; }
ll sum(int x, ll r = 0) { for(int i = x; i >= 1; i -= lowbit(i)) r += tr[i]; return r; }
void build()
{
    for(int i = 0; i < 26; i++) if(trie[0][i]) q.push(trie[0][i]);
    while(!q.empty())
    {
        int u = q.front(); q.pop();
        for(int i = 0; i < 26; i++)
            if(trie[u][i])
            {
                fail[trie[u][i]] = trie[fail[u]][i];
                q.push(trie[u][i]);
            }else { trie[u][i] = trie[fail[u]][i]; }
        vec[fail[u]].push_back(u);
    }
}
void dfs(int u)
{
    static int tim = 0; dfn[u] = ++tim; sz[u] = 1;
    for(int v : vec[u]) { dfs(v), sz[u] += sz[v]; }
}
void insert(int id)
{
    int u = 0;
    for(int i = 1; s[i]; i++)
    {
        int c = s[i] - 'a';
        if(!trie[u][c]) trie[u][c] = ++tot;
        u = trie[u][c];
    }
    ed[id] = u;
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    int qwq, n; cin >> qwq >> n;
    for(int i = 1; i <= n; i++) { cin >> (s + 1); insert(i); }
    build(); dfs(0);
    for(int i = 1; i <= n; i++)
    {
        const int id = ed[i]; live[i] = true;
        add(dfn[id], 1); add(dfn[id] + sz[id], -1);
    }
    while(qwq--)
    {
        char ch; cin >> ch;
        if(ch == '?')
        {
            int p = 0; ll res = 0; cin >> (s + 1);
            for(int i = 1; s[i]; i++) {
                p = trie[p][s[i] - 'a']; res += sum(dfn[p]);
            }
            cout << res << '\n';
        }else if(ch == '-')
        {
            int id; cin >> id; if(!live[id]) continue;
            live[id] = false; id = ed[id];
            add(dfn[id], -1); add(dfn[id] + sz[id], 1);
        }else if(ch == '+')
        {
            int id; cin >> id; if(live[id]) continue;
            live[id] = true; id = ed[id];
            add(dfn[id], 1); add(dfn[id] + sz[id], -1);
        }
    }
    return 0;
}

文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录