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;

}

  

 

你可能感兴趣的:(ZOJ)