zoukankan      html  css  js  c++  java
  • Divljak

    Divljak

    Alice 有 $n$ 个字符串 $ S_1,S_2,cdots,S_n $ ,Bob有一个字符串集合 $T$ ,一开始集合是空的。

    接下来会发生 $q$ 个操作,操作有两种形式:

    “ $1~P$ ”,Bob 往自己的集合里添加了一个字符串 $P$ 。

    “ $2~x$ ”,Alice 询问 Bob,集合 $T$ 中有多少个字符串包含串 $S_x$ 。

    (我们称串 $A$ 包含串 $B$ ,当且仅当 $B$ 是 $A$ 的子串)

    Bob 遇到了困难,需要你的帮助。


    Sol

    考虑S集建AC自动机。

    每次把新加入的串扔进去匹配,所有匹配位置加1。

    查询时就是子树和。

    但是有重复算的情况。我们把所有要加的点按dfs序排序,然后把相邻两两的lca-1

    这样就不重了,lca之上的点会+2-1

    卡常差评

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #define maxn 2000006
    using namespace std;
    int num,n,tr[maxn][26],fail[maxn],p[maxn],tot,cnt;
    int head[maxn],f[maxn],deep[maxn],dfn[maxn],sc;
    int son[maxn],sz[maxn],top[maxn],tree[maxn],a[maxn];
    struct node{
        int v,nex;
    }e[maxn*2];
    char s[maxn];
    void ins(int id){
        int len=strlen(s),k=0;
        for(int i=0;i<len;i++){
            if(!tr[k][s[i]-'a'])tr[k][s[i]-'a']=++n;
            k=tr[k][s[i]-'a'];
        }
        p[id]=k;
    }
    void build(){
        queue<int>q;
        for(int i=0;i<26;i++)if(tr[0][i])q.push(tr[0][i]);
        while(!q.empty()){
            int k=q.front();q.pop();
            for(int i=0;i<26;i++){
                if(tr[k][i]){
                    fail[tr[k][i]]=tr[fail[k]][i];
                    q.push(tr[k][i]);
                }
                else tr[k][i]=tr[fail[k]][i];
            }
        }
    }
    void lj(int t1,int t2){
        e[++tot].v=t2;e[tot].nex=head[t1];head[t1]=tot;
    }
    void dfs1(int k,int fa){
        f[k]=fa;deep[k]=deep[fa]+1;
        sz[k]=1;int gp=0;
        for(int i=head[k];i;i=e[i].nex){
            dfs1(e[i].v,k);
            sz[k]+=sz[e[i].v];
            if(sz[e[i].v]>sz[gp] || !gp)gp=e[i].v;
        }
        son[k]=gp;
    }
    void dfs2(int k){
        dfn[k]=++sc;
        if(son[k])top[son[k]]=top[k],dfs2(son[k]);
        for(int i=head[k];i;i=e[i].nex)
            if(e[i].v!=son[k])top[e[i].v]=e[i].v,dfs2(e[i].v);
    }
    void add(int i,int v){
        for(;i<=n;i+=i&-i)tree[i]+=v;
    }
    int ask(int i){
        int sum=0;for(;i;i-=i&-i)sum+=tree[i];
        return sum;
    }
    bool cmp(int a,int b){
        return dfn[a]<dfn[b];
    }
    int lca(int a,int b){
        int t1=top[a],t2=top[b];
        while(t1!=t2){
            if(deep[t1]<deep[t2])swap(t1,t2);
            a=f[t1],t1=top[a];
        }
        return deep[a]>deep[b]?b:a;
    }
    void work(){
        int tp=0;
        int k=0;int len=strlen(s);
        for(int i=0;i<len;i++){
            k=tr[k][s[i]-'a'];a[++tp]=k;
            //add(dfn[k],1);
        }
        sort(a+1,a+tp+1,cmp);
        add(dfn[a[1]],1);
        for(int i=2;i<=tp;i++)add(dfn[a[i]],1),add(dfn[lca(a[i],a[i-1])],-1);
    }
    int main()
    {
        scanf("%d",&num);
        for(int i=1;i<=num;i++){
            scanf(" %s",s);ins(i);
        }
        build();
         
        for(int i=1;i<=n;i++)lj(fail[i],i);
        n++;dfs1(0,n);dfs2(0);
        int q;scanf("%d",&q);
        for(int i=1,op;i<=q;i++){
            scanf("%d",&op);
            if(op==1){
                scanf("%s",s);work();
            }
            else {
                int t;scanf("%d",&t);t=p[t];
                printf("%d
    ",ask(dfn[t]+sz[t]-1)-ask(dfn[t]-1));
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    SAP函数生成测试数据
    ABAP——编码规范
    展BOM清单——CS_BOM_EXPL_MAT_V2
    Java使用JCO实现调用SAP接口(建立采购单)
    ECN变更单建立——CCAP_ECN_CREATE
    SmartForms——插入复选框
    SmartForms——属性框被拖拽到左边不能复原
    SmartForms——实例
    SmartForms——基础知识
    SAP PP——生产订单的状态
  • 原文地址:https://www.cnblogs.com/liankewei/p/10667141.html
Copyright © 2011-2022 走看看