BZOJ2434 [NOI2011] Ali typewriter

Knowledge points:

AC automata, fail tree, offline, Fenwick tree, Chairman of the tree

Meaning of the questions:

Given a number of strings, several interrogation (x, y) x string appears many times in the y-stream, in addition to range (lower case letters) are outside the range of 1e5.

solution:

First of all, according to which a given "typewriter read mode", we can jump on trie, a simulation of this process. Encounter lowercase letters, then jump (not to insert a new point), met \ (B \) to jump back at his father (so trie need to maintain the number of each point father points), met \ (P \) to mark at the end of the node (if the original a bit, then put the current string of fa as the original string, or add a number). If this is not according to the above method, it is bound on the complexity of the \ (O (n ^ 2) \) a.

Next, consider a single (x, y) how to match. Note entitled to ask is how many times x appears in y, we have to clear a few properties.

  • ACAM node on a path to the root node, each point on the path is a prefix of the current point. With trie to understand this is very evident when.
  • A fail path tree nodes to the root node, a point on each of the current paths are point suffix, and the suffix must be a monotonically decreasing sequence length.

Here add what tree do fail, fail the tree is a pointer to fail to connect the reverse form of a tree, with a lot of very beautiful nature.

So we have two more by nature, we can find, ask the number that appears in y x, x there is to ask subtree fail tree how many points is an ancestor of y nodes fail the corresponding node of the tree (including y themselves).

Therefore, we consider how to maintain the information above.

If you do online, then each traversing a fail tree, is \ (O (n ^ 2) \) , so we have to ask all offline down, because y is asked as a text string, so you can choose the sorting process y . But I chose to open a vector directly to the corresponding y fa (that is, when inserting the same words on the record that fa) numbers hang on the corresponding ACAM, the x also hang after treatment.

Consider the DFS tree fail to get out of order (as in a subtree rooted at the node must be a contiguous stretch of sequence in the DFS), it can be converted into a sequence of data problems Fenwick tree structure to maintain the like. Because every time recovering from the impact of a node that happens is 1, the DFS over the trie (Note that before seeking to put all the son fail to back up again, otherwise it will be connected to some point they had no), one to one put the current point in the point array +1 point DFS tree fail sequence corresponding to the tree, and then asked to answer all the current point (x points are points -x right subtree point to point left subtree value), then traverse all true sons and -1 to leave.

note:

  1. Find out what time is fail, what time is trie. Here understanding substring personally think that analogy SAM, because a substring suffix = suffix prefix = prefix, it is traversing the trie tree, but the tree-like array maintenance of order in the DFS tree fail.
  2. If you're thinking, why not add the number of all of the string at the end of a child's place, but +1? Is entitled to ask it is because the number of times x appears in y, even if a lot of times, it is only counted once.

Code:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;

const int maxn=100010;
int n,m,head[maxn],etot,tot=1,c[maxn],dfn[maxn],low[maxn],fa[maxn],cnt,ans[maxn],id[maxn];
struct node
{
    int nxt,to;
}edge[maxn];
struct trie
{
    int son[26],fail,tag,fa,ch[26];
}a[maxn];
struct pro
{
    int x,id;
};
vector<pro>que[maxn];
queue<int>q;
char s[maxn];

int read()
{
    int x=0;
    char c=getchar();
    while (c<48||c>57)
        c=getchar();
    while (c>=48&&c<=57)
        x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x;
}

void insert(char *s)
{
    int i,u=1,len=strlen(s),k;
    a[1].fa=1;
    for (i=0;i<len;i++)
    {
        if (s[i]>='a'&&s[i]<='z')
        {
            k=s[i]-'a';
            if (!a[u].son[k])
            {
                a[u].son[k]=(++tot);
                a[tot].fa=u;
            }
            u=a[u].son[k];
        }
        if (s[i]=='B')
            u=a[u].fa;
        if (s[i]=='P')
        {
            id[++n]=u;
            fa[n]=n;
            if (a[u].tag)
                fa[n]=a[u].tag;
            else
                a[u].tag=n;
        }
    }
}

void getfail()
{
    int i,u,v,fafail;
    for (i=0;i<=25;i++)
        a[0].son[i]=1;
    a[1].fail=0;
    q.push(1);
    while (!q.empty())
    {
        u=q.front();
        q.pop();
        fafail=a[u].fail;
        for (i=0;i<=25;i++)
        {
            v=a[u].son[i];
            if (!v)
                a[u].son[i]=a[fafail].son[i];
            else
            {
                a[v].fail=a[fafail].son[i];
                q.push(v);
            }
        }
    }
}

void add(int u,int v)
{
    edge[++etot]=(node){head[u],v};
    head[u]=etot;
}

int lowbit(int x)
{
    return x&-x;
}

void update(int x,int val)
{
    for (;x<=cnt;x+=lowbit(x))
        c[x]+=val;  
}

int query(int x)
{
    int res=0;
    for (;x;x-=lowbit(x))
        res+=c[x];
    return res;
}

void DFS(int u)
{
    int i;
    dfn[u]=(++cnt);
    for (i=head[u];i;i=edge[i].nxt)
        DFS(edge[i].to);
    low[u]=cnt;
}

void dfs(int u)
{
    update(dfn[u],1);
    int i,siz=que[u].size();
    for (i=0;i<siz;i++)
        ans[que[u][i].id]=query(low[que[u][i].x])-query(dfn[que[u][i].x]-1);
    for (i=0;i<=25;i++)
        if (a[u].ch[i])
            dfs(a[u].ch[i]);
    update(dfn[u],-1);
}

int main()
{
    int i,j,u,v;
    scanf("%s",s);
    insert(s);
    for (i=1;i<=tot;i++)
        for (j=0;j<=25;j++)
            a[i].ch[j]=a[i].son[j];
    getfail();
    for (i=1;i<=tot;i++)
        if (a[i].fail!=i&&a[i].fail>=1)
            add(a[i].fail,i);
    DFS(1);
    m=read();
    for (i=1;i<=m;i++)
    {
        u=id[fa[read()]],v=id[fa[read()]];
        que[v].push_back((pro){u,i});
    }
    dfs(1);
    for (i=1;i<=m;i++)
        printf("%d\n",ans[i]);
    return 0;
}

Guess you like

Origin www.cnblogs.com/Ronald-MOK1426/p/12236634.html