码迷,mamicode.com
首页 > 其他好文 > 详细

字符串

时间:2019-08-07 09:28:23      阅读:103      评论:0      收藏:0      [点我收藏+]

标签:图片   long   return   abs   rom   ems   复杂   出现   输入   

题目

Description
技术图片
Input
技术图片

Output
技术图片

题解

显然用是AC自动机来解决

先说一下没人写的正解
二进制分组, 建\(O(lgm)\)个AC自动机。 定义AC自动机的size为这个AC自动机中的字符串个数。 当两个AC自动机size相等时合并这两个AC自动机。时间复杂度\(O(mlgm)\)

下面是比较好想, 也比较常规的做法。
题目中说强制在线, 但是却没有给字符串加密。 于是我们不一定要真的在线做。 我们可以用输入中出现的所有字符串建一个AC自动机, 虽然这样会把询问串也包含在内但对结果没有影响。
每次查询还是正常的在AC自动机上走。但由于是动态修改, 我们无法像正常的AC自动机一样预处理, 于是我们需要维护fail树。
把所有fail边拿出来建建一颗树。 然后问题转化成了: 修改一个点的权值, 询问一个点到根路径的权值和。 然后随便用数据结构维护就好了。

代码

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <algorithm>

#include <queue>

using namespace std;


typedef long long LL;


const int N = 1000010, M = 2000010;


int ed[N];


struct AC
{
    static const int SIZE = 1000010;
    
    int nxt[SIZE][26], fail[SIZE];
    LL val[SIZE];
    int root;
    int sz;

    AC() { }

    void init()
    {
        sz = 0;
        root = newnode();
    }

    int newnode()
    {
        memset(nxt[sz], 0, sizeof(nxt[sz]));
        fail[sz] = 0;
        val[sz] = 0;
        return sz++;
    }
    
    void insert(char * str, int len, int id)
    {
        int u = root;
        
        for (int i = 0; i < len; i++)
        {
            int c = str[i] - 'a';
            if (!nxt[u][c])
                nxt[u][c] = newnode();
            u = nxt[u][c];
        }
        
        ed[id] = u;
    }

    void getFail()
    {
        queue <int> q;
        
        for (int i = 0; i < 26; i++)
            if (nxt[root][i])
            {
                fail[nxt[root][i]] = root;
                q.push(nxt[root][i]);
            }
            else nxt[root][i] = root;
        
        while (!q.empty())
        {
            int x = q.front(); q.pop();
            for (int i = 0; i < 26; i++)
            {
                if (nxt[x][i])
                {
                    fail[nxt[x][i]] = nxt[fail[x]][i];
                    q.push(nxt[x][i]);
                }
                else nxt[x][i] = nxt[fail[x]][i];
            }
        }
    }
} ac;


struct edge
{
    int from, to;
    edge() { }
    edge(int _1, int _2) : from(_1), to(_2) { }
} edges[M];

int head[N], nxt[M], tot;

inline void init()
{
    memset(head, -1, sizeof(head));
    tot = 0;
}

inline void add_edge(int x, int y)
{
    edges[tot] = edge(x, y);
    nxt[tot] = head[x];
    head[x] = tot++;
    edges[tot] = edge(y, x);
    nxt[tot] = head[y];
    head[y] = tot++;
}


int dfn[N], idf[N], siz[N], dfs_clock;

void dfs(int x, int fa)
{
    dfn[x] = ++dfs_clock;
    idf[dfn[x]] = x;
    siz[x] = 1;
    
    for (int i = head[x]; ~i; i = nxt[i])
    {
        edge & e = edges[i];
        if (e.to != fa)
        {
            dfs(e.to, x);
            siz[x] += siz[e.to];
        }
    }
}


struct Calc
{
    LL val[N];

    void upd(int x, int v)
    {
        for (int i = x; i <= dfs_clock; i += (i & -i))
            val[i] += v;
    }

    LL qry(int x)
    {
        LL Ans = 0;
        for (int i = x; i > 0; i -= (i & -i))
            Ans += val[i];
        return Ans;
    }
} Calc;


int m;


int opt[N];


char str[N];
int L[N], R[N];


int main()
{
    scanf("%d", &m);
    
    ac.init();
    
    for (int i = 1; i <= m; i++)
    {
        scanf("%d", &opt[i]);
        L[i] = R[i-1] + 1;
        scanf("%s", str + L[i]);
        R[i] = L[i] + strlen(str + L[i]) - 1;
        ac.insert(str + L[i], R[i] - L[i] + 1, i);
    }
    
    ac.getFail();
    
    init();
    
    for (int i = 1; i < ac.sz; i++)
        add_edge(ac.fail[i], i);
    
    dfs(0, -1);
    
    int mask = 0;
    
    for (int i = 1; i <= m; i++)
    {
        opt[i] ^= mask;
        if (opt[i] == 1)
        {
            int x = ed[i];
            int l = dfn[x], r = dfn[x] + siz[x] - 1;
            Calc.upd(l, 1);
            Calc.upd(r + 1, -1);
        }
        else if (opt[i] == 2)
        {
            int x = ed[i];
            int l = dfn[x], r = dfn[x] + siz[x] - 1;
            Calc.upd(l, -1);
            Calc.upd(r + 1, 1);
        }
        else
        {
            LL Ans = 0;
            int u = ac.root;
            for (int j = L[i]; j <= R[i]; j++)
            {
                u = ac.nxt[u][str[j] - 'a'];
                Ans += Calc.qry(dfn[u]);
            }
            mask ^= abs(Ans);
            printf("%lld\n", Ans);
        }
    }
    
    return 0;
}

字符串

标签:图片   long   return   abs   rom   ems   复杂   出现   输入   

原文地址:https://www.cnblogs.com/2016gdgzoi509/p/11313066.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!