• BZOJ3881 : [Coci2015]Divljak


    对Alice的所有串构造AC自动机,并建出Fail树

    每当Bob添加一个串时,在AC自动机上走,每走到一个点,就把它到根路径上所有点的答案+1

    需要注意的是每次操作,相同的点只能被加一次

    所以在需要操作的点构成的虚树上进行修改操作,避免重复修改

    对于修改,x到根路径上所有点答案+1等价于在x点打上一个标记,对于所有祖先都有效

    由此将问题转化为单点修改,子树查询

    树状数组维护

    注意到关键点其实只有n个,所以可以一开始先对这n个点求一次虚树来降低常数

    时间复杂度$O(Llog L)$,L为所有串的长度之和

    #include<cstdio>
    #include<algorithm>
    #define N 2000010
    using namespace std;
    int tot,son[N][26],f[N],v[N],nxt[N],g[N],ed,q[N],h=1,t=1;
    int size[N],heavy[N],d[N],top[N],st[N],en[N],dfn,bit[N],fin[100010],fir[N],fa[N];
    int m,a[N],b[N];bool vis[N],have[N];
    int n,Q,i,k,j,x,op,l;
    int need[N],cn;
    char s[N],c;
    inline void read(int&a){while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
    inline void readstr(){for(l=0;((c=getchar())>='a')&&(c<='z');s[l++]=c);}
    inline bool cmp(int x,int y){return st[x]<st[y];}
    inline void ins(int p){
      for(int x=0,i=0,w;i<l;i++){
        if(!son[x][w=s[i]-'a'])son[x][w]=++tot;x=son[x][w];
        if(i==l-1)fin[p]=x;
      }
    }
    inline void add(int x,int y){fa[y]=x;v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
    void dfs(int x){
      st[x]=++dfn;d[x]=d[fa[x]]+1;size[x]=1;heavy[x]=-1;
      for(int i=g[x];i;i=nxt[i])if(v[i]!=fa[x]){
        dfs(v[i]);size[x]+=size[v[i]];
        if(heavy[x]<0||size[v[i]]>size[heavy[x]])heavy[x]=v[i];
      }
      en[x]=dfn;
    }
    void dfs2(int x,int y){
      top[x]=y;
      if(~heavy[x])dfs2(heavy[x],y);
      for(int i=g[x];i;i=nxt[i])if(v[i]!=heavy[x]&&v[i]!=fa[x])dfs2(v[i],v[i]);
    }
    void dfs3(int x,int y){
      if(vis[x])y=x;
      fir[x]=y;
      for(int i=g[x];i;i=nxt[i])if(v[i]!=fa[x])dfs3(v[i],y);
    }
    inline int lca(int x,int y){
      for(;top[x]!=top[y];x=fa[top[x]])if(d[top[x]]<d[top[y]])swap(x,y);
      return d[x]<d[y]?x:y;
    }
    inline void modify(int x,int y){for(;x<=dfn;x+=x&-x)bit[x]+=y;}
    inline int sum(int x){t=0;for(;x;x-=x&-x)t+=bit[x];return t;}
    inline void match(){
      for(int x=0,i=m=0,w;i<l;i++){
        w=s[i]-'a';
        while(x&&!son[x][w])x=f[x];x=son[x][w];
        if(!vis[fir[x]])vis[a[++m]=fir[x]]=1;
      }
    }
    int main(){
      for(read(n),i=1;i<=n;i++)readstr(),ins(i);
      f[0]=-1;
      while(h<=t)for(x=q[h++],i=0;i<26;i++)if(son[x][i])for(q[++t]=son[x][i],j=f[x];~j;j=f[j])if(x&&son[j][i]){f[son[x][i]]=son[j][i];break;}
      for(i=1;i<=tot;i++)add(f[i],i);
      dfs(0),dfs2(0,0);
      vis[0]=m=1;
      for(i=1;i<=n;i++)if(!vis[fin[i]])vis[a[++m]=fin[i]]=1;
      sort(a+1,a+m+1,cmp);
      for(cn=m,i=1;i<m;i++)if(!vis[x=lca(a[i],a[i+1])])vis[a[++cn]=x]=1;
      dfs3(0,0);
      for(ed=i=0;i<=tot;i++)g[i]=0;
      m=cn,sort(a+1,a+m+1,cmp);
      for(q[t=1]=0,i=2;i<=m;q[++t]=a[i++]){
        while(st[a[i]]<st[q[t]]||en[a[i]]>en[q[t]])t--;
        add(q[t],a[i]);
      }
      for(i=1;i<=m;i++)vis[a[i]]=0;
      dfs(dfn=cn=0);dfs2(0,0);
      read(Q);
      while(Q--){
        read(op);
        if(op==1){
          readstr();
          match();
          sort(a+1,a+m+1,cmp);
          for(tot=m,i=1;i<m;i++)if(!vis[x=lca(a[i],a[i+1])])vis[a[++tot]=x]=1;
          m=tot,sort(a+1,a+m+1,cmp);
          if(!have[x=a[1]])have[x]=1,b[x]=0,need[++cn]=x;b[x]++;
          for(q[t=1]=a[1],i=2;i<=m;q[++t]=a[i++]){
            while(st[a[i]]<st[q[t]]||en[a[i]]>en[q[t]])t--;
            if(!have[x=q[t]])have[x]=1,b[x]=0,need[++cn]=x;b[x]--;
            if(!have[x=a[i]])have[x]=1,b[x]=0,need[++cn]=x;b[x]++;
          }
          for(i=1;i<=m;i++)vis[a[i]]=0;
        }else{
          if(cn){
            for(i=1;i<=cn;i++)x=need[i],modify(st[x],b[x]),have[x]=b[x]=0;
            cn=0;
          }
          read(x),x=fin[x],printf("%d
    ",sum(en[x])-sum(st[x]-1));
        }
      }
      return 0;
    }
    

      

  • 相关阅读:
    div定位
    学习进度条(第十周)
    学习进度条(第九周)
    软件工程个人作业--找水王
    个人NABCD
    梦断代码阅读笔记01---死定了
    进度条(第八周)
    学习进度条(第七周)
    软件工程结对开发作业02---二维数组求最大连通子数组
    软件工程结对作业01--四则运算Web版
  • 原文地址:https://www.cnblogs.com/clrs97/p/4403152.html
Copyright © 2020-2023  润新知