zoukankan      html  css  js  c++  java
  • BZOJ3906 : Trie

    将输入的Trie建成AC自动机,并建出fail树。

    那么操作1等价于在给定点的子树的并集里都加1。

    操作2等价于查询给定点到根节点路径的并集的权值和。

    求出DFS序后,对于操作1,将点按进入时间戳从小到大排序,然后求出并集,进行区间修改即可。

    对于操作2,构造给定点集的虚树,在虚树的每一条边上询问权值和,累加起来即可。

    对于子树修改,链查询,可以使用4棵树状数组维护。

    时间复杂度$O((m+k)log n)$。

    #include<cstdio>
    #include<algorithm>
    #define N 100010
    using namespace std;
    typedef long long ll;
    int Case,n,Q,i,j,x,op,ch[N][26],f[N],g[N],nxt[N];
    int d[N],size[N],son[N],top[N],st[N],en[N],dfn;
    int m,q[N],a[N],tot,t,vis[N];
    struct BIT{
      int n,s[N<<1],a[N<<1];ll b[N<<1];
      inline void init(int x){n=x;for(int i=1;i<=n;i++)a[i]=b[i]=s[i]=0;}
      inline void modify(int x,int p){for(int i=x;i<=n;i+=i&-i)a[i]+=p,b[i]+=p*s[x-1];}
      inline ll ask(int x){
        int t0=0;ll t1=0;
        for(int i=x;i;i-=i&-i)t0+=a[i],t1+=b[i];
        return 1LL*s[x]*t0-t1;
      }
      inline void add(int x,int y){modify(x,1),modify(y+1,-1);}
    }ti,to;
    inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
    inline int getch(){char c;while(!(((c=getchar())>='a')&&(c<='z')));return c;}
    inline void make(){
      int h=1,t=0,i,j,x;
      for(i=0;i<26;i++)if(ch[1][i])f[q[++t]=ch[1][i]]=1;else ch[1][i]=1;
      while(h<=t)for(x=q[h++],i=0;i<26;i++)if(ch[x][i])f[ch[x][i]]=ch[f[x]][i],q[++t]=ch[x][i];else ch[x][i]=ch[f[x]][i];
    }
    void dfs(int x){
      d[x]=d[f[x]]+1,size[x]=1,son[x]=0;
      for(int i=g[x];i;i=nxt[i]){
        dfs(i),size[x]+=size[i];
        if(size[i]>size[son[x]])son[x]=i;
      }
    }
    void dfs2(int x,int y){
      top[x]=y;st[x]=++dfn;
      if(son[x])dfs2(son[x],y);
      for(int i=g[x];i;i=nxt[i])if(i!=son[x])dfs2(i,i);
      en[x]=++dfn;
    }
    inline int lca(int x,int y){
      for(;top[x]!=top[y];x=f[top[x]])if(d[top[x]]<d[top[y]])swap(x,y);
      return d[x]<d[y]?x:y;
    }
    inline int cmp(int x,int y){return st[x]<st[y];}
    int main(){
      read(Case);
      while(Case--){
        read(n);
        for(i=2;i<=n;i++)read(x),ch[x][getch()-'a']=i;
        make();
        for(i=2;i<=n;i++)nxt[i]=g[f[i]],g[f[i]]=i;
        dfs(1),dfs2(1,1);
        ti.init(dfn),to.init(dfn);
        for(i=1;i<=n;i++)ti.s[st[i]]=1,to.s[en[i]]=-1;
        for(i=2;i<=dfn;i++)ti.s[i]+=ti.s[i-1],to.s[i]+=to.s[i-1];
        read(Q);
        while(Q--){
          read(op),read(m);
          if(op==1){
            for(i=0;i<m;i++)read(a[i]);
            for(sort(a,a+m,cmp),j=i=0;i<m;i++)if(st[a[i]]>j){
              ti.add(st[a[i]],en[a[i]]);
              to.add(st[a[i]],en[a[i]]);
              j=en[a[i]];
            }
          }else{
            for(tot=i=0;i<m;i++){
              read(x);
              if(!vis[x])vis[a[++tot]=x]=1;
            }
            if(!vis[1])vis[a[++tot]=1]=1;
            m=tot,sort(a+1,a+m+1,cmp);
            for(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);
            ll ans=ti.ask(1);
            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--;
              ans+=ti.ask(st[a[i]])+to.ask(st[a[i]])-ti.ask(st[q[t]])-to.ask(st[q[t]]);
            }
            for(i=1;i<=m;i++)vis[a[i]]=0;
            printf("%lld
    ",ans);
          }
        }
        for(dfn=0,i=1;i<=n;i++)for(f[i]=g[i]=j=0;j<26;j++)ch[i][j]=0;
      }
      return 0;
    }
    

      

  • 相关阅读:
    MySQL5.7(64位)windows下的安装
    Python---更改pip源
    .NET WEB技术小记
    前端板书1
    Hadoop伪分布式系统的搭建(ubuntu)
    Hive的基本操作
    SQLServer2008附加数据库不成功 操作系统错误5
    VUE学习小结
    jQuery入门基础(选择器)
    Linq(高级查询)
  • 原文地址:https://www.cnblogs.com/clrs97/p/4856613.html
Copyright © 2011-2022 走看看