zoukankan      html  css  js  c++  java
  • BZOJ3879 : SvT

    求出S串的后缀树,则两个后缀的lcp等于其lca到根的距离

    对于每次询问,对这些节点构造虚树,然后树形DP即可

    #include<cstdio>
    #include<algorithm>
    using std::sort;
    typedef long long ll;
    const int inf=1<<25,S=28,N=1000010;
    const ll P=23333333333333333LL;
    char tmp[N],ch;
    int text[N],root,last,pos,need,remain,acnode,ace,aclen;
    int Q,n,m,i,x,y;
    int dfn,st[N],en[N],id[N],d[N],f[N],son[N],size[N],top[N];
    int a[N],q[N],g[N],nxt[N],v[N],ed,tot,t;
    bool vip[N],vis[N];
    ll ans;
    inline bool cmp(int x,int y){return st[x]<st[y];}
    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 min(int a,int b){return a<b?a:b;}
    inline void swap(int&a,int&b){int c=a;a=b;b=c;}
    inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
    struct node{int st,en,lk,son[S];inline int len(){return min(en,pos+1)-st;}}tree[N];
    inline int new_node(int st,int en=inf){return tree[++last].st=st,tree[last].en=en,last;}
    inline int acedge(){return text[ace];}
    inline void addedge(int node){
      if(need)tree[need].lk=node;
      need=node;
    }
    inline bool down(int node){
      if(aclen>=tree[node].len())return ace+=tree[node].len(),aclen-=tree[node].len(),acnode=node,1;
      return 0;
    }
    inline void init(){
      need=last=remain=ace=aclen=0;
      root=acnode=new_node(pos=-1,-1);
    }
    inline void extend(int c){
      text[++pos]=c;need=0;remain++;
      while(remain){
        if(!aclen)ace=pos;
        if(!tree[acnode].son[acedge()])tree[acnode].son[acedge()]=new_node(pos),addedge(acnode);
        else{
          int nxt=tree[acnode].son[acedge()];
          if(down(nxt))continue;
          if(text[tree[nxt].st+aclen]==c){aclen++;addedge(acnode);break;}
          int split=new_node(tree[nxt].st,tree[nxt].st+aclen);
          tree[acnode].son[acedge()]=split;
          tree[split].son[c]=new_node(pos);
          tree[nxt].st+=aclen;
          tree[split].son[text[tree[nxt].st]]=nxt;
          addedge(split);
        }
        remain--;
        if(acnode==root&&aclen)aclen--,ace=pos-remain+1;
        else acnode=tree[acnode].lk?tree[acnode].lk:root;
      }
    }
    void dfs(int x,int sum){
      d[x]=sum+=tree[x].len();size[x]=1;
      if(tree[x].en==inf)id[pos-sum+2]=x;
      st[x]=++dfn;
      for(int i=0;i<S;i++)if(tree[x].son[i]){
        add(x,tree[x].son[i]);
        f[tree[x].son[i]]=x;
        dfs(tree[x].son[i],sum);
        size[x]+=size[tree[x].son[i]];
        if(size[tree[x].son[i]]>size[son[x]])son[x]=tree[x].son[i];
      }
      en[x]=dfn;
    }
    void dfs2(int x,int y){
      top[x]=y;
      if(son[x])dfs2(son[x],y);
      for(int i=g[x];i;i=nxt[i])if(v[i]!=son[x]&&v[i]!=f[x])dfs2(v[i],v[i]);
    }
    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 ll mul(ll a,int b){ll t=0;for(;b;b>>=1,(a<<=1)%=P)if(b&1)(t+=a)%=P;return t;}
    void dp(int x){
      size[x]=0;
      ll tmp=0;
      for(int i=g[x];i;i=nxt[i]){
        dp(v[i]);
        (tmp+=(ll)size[x]*size[v[i]]%P)%=P;
        size[x]+=size[v[i]];
      }
      (ans+=mul(tmp,d[x]))%=P;
      size[x]+=vip[x];
    }
    int main(){
      init();
      read(n),read(Q);
      for(i=1;i<=n;tmp[i++]=ch)while(!(((ch=getchar())>='a')&&(ch<='z')));
      for(i=1;i<=n;i++)extend(tmp[i]-'a'+1);extend(27);
      dfs(root,0),dfs2(root,root);
      for(i=1;i<=last;i++)g[i]=0;
      while(Q--){
        read(m);
        for(ans=tot=0,i=1;i<=m;i++){
          read(x);
          if(!vis[x=id[x]])vis[a[++tot]=x]=vip[x]=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);
        for(ed=0,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--;
          add(q[t],a[i]);
        }
        dp(a[1]);
        for(i=1;i<=m;i++)vis[a[i]]=vip[a[i]]=g[a[i]]=0;
        printf("%lld
    ",ans);
      }
      return 0;
    }
    

      

  • 相关阅读:
    寒假Day37:设计模式(封装+继承+多态等)
    INF ClassInstall32 Section详解
    VS2008编译的程序运行提示“由于应用程序配置不正确,应用程序未能启动”
    INF Models Section
    INF DDInstall.Services Section
    INF ClassInstall32.Services Section详解
    INF DDInstall Section
    INF SourceDisksNames Section 和 SourceDisksFiles Section详解
    sys文件查看DbgPrint函数打印的信息
    IRP(I/O Request Package)详解
  • 原文地址:https://www.cnblogs.com/clrs97/p/4403155.html
Copyright © 2011-2022 走看看