• CodeForces


    题意:有N个串,给出的形式是拼接给出,对于第i行:  (1,c)表示字符串i是单个字母c; (2,p,c)表示字符串i=在字符串p后面接上一个字母c。

              然后给出M个提问,形式是(i,string)。问string在字符串i中出现了多少次。

    思路:这类题显然是在AC自动机上乱搞。  对于询问的串建立AC自动机,BFS建立fail树;那么一个询问其实就是第i个串的位置到根的这些节点,有多少个在string节点的子树里。      即给一条链染色,然后询问一个点是子树里多少点被染色了。 为了不重不漏,  我们用回溯就可以处理了。 然后用树状数组维护DFS序下的前缀和。  

    具体的,对于N个串在AC自动机上跑,每跑一步对应N个字符串之一。 每跑到一个节点,就加加。 跑完子树后就减减,保证了加的部分是一条链。 

    #include<bits/stdc++.h>
    #define pii pair<int,int>
    #define pb push_back
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=400010;
    vector<pii>G[maxn],Q[maxn];
    vector<int>F[maxn];
    int ch[maxn][26],fail[maxn],ans[maxn],tot;
    int in[maxn],out[maxn],times; //dfn
    char s[maxn]; int sum[maxn];
    void add(int x,int val){ while(x<=times) sum[x]+=val,x+=(-x)&x;}
    int query(int x){ int res=0; while(x){ res+=sum[x]; x-=(-x)&x; } return res;}
    int add()
    {
        int now=0,L=strlen(s);
        rep(i,0,L-1) {
            if(!ch[now][s[i]-'a']) ch[now][s[i]-'a']=++tot;
            now=ch[now][s[i]-'a'];
        }  return now;
    }
    void build()
    {
        queue<int>q;
        rep(i,0,25) if(ch[0][i]) q.push(ch[0][i]);
        while(!q.empty()){
            int u=q.front(); q.pop();
            rep(i,0,25) {
                if(ch[u][i]){
                    fail[ch[u][i]]=ch[fail[u]][i];
                    q.push(ch[u][i]);
                }
                else ch[u][i]=ch[fail[u]][i];
            }
        }
        rep(i,1,tot) F[fail[i]].push_back(i);
    }
    void dfs(int u)
    {
        in[u]=++times;
        for(int i=0;i<F[u].size();i++) dfs(F[u][i]);
        out[u]=times;
    }
    void dfs(int u,int now) //u是位置,now是id
    {
        add(in[u],1);
        for(int i=0;i<Q[now].size();i++){
            pii t=Q[now][i];
            ans[t.second]=query(out[t.first])-query(in[t.first]-1);
        }
        for(int i=0;i<G[now].size();i++){
            pii t=G[now][i];
            dfs(ch[u][t.first],t.second);
        }
        add(in[u],-1);
    }
    int main()
    {
        int N,M,opt,p;
        scanf("%d",&N);
        rep(i,1,N) {
            scanf("%d",&opt);
            if(opt==1) p=0;
            else scanf("%d",&p);
            scanf("%s",s);
            G[p].pb(pii(s[0]-'a',i));
        }
        scanf("%d",&M);
        rep(i,1,M) {
            scanf("%d%s",&p,s);
            Q[p].pb(pii(add(),i));
        }
        build();
        dfs(0);
        dfs(0,0);
        rep(i,1,M) printf("%d
    ",ans[i]);
        return 0;
    }
  • 相关阅读:
    Codeforces Round #632 (Div. 2) D-Challenges in school №41(模拟好题)
    余数求和
    B. 齐心抗疫
    MyBatis源码分析
    关于Idea中右边的maven projects窗口找不到了如何调出来
    IDEA java类文件左下角出现红色的J标识,解决方法
    Postman Tests脚本的使用
    JSONPath解析json
    Postman + Newman 生成测试报告
    TestNG 多线程测试
  • 原文地址:https://www.cnblogs.com/hua-dong/p/11428642.html
Copyright © 2020-2023  润新知