zl程序教程

您现在的位置是:首页 >  其它

当前栏目

BZOJ3906 : Trie

Trie
2023-09-11 14:15:04 时间

将输入的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\n",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;
}