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\n",ans);
  }
  return 0;
}

  

 

posted @ 2015-01-18 12:40  Claris  阅读(572)  评论(0编辑  收藏  举报