zoukankan      html  css  js  c++  java
  • [Jsoi2015]字符串树

    https://www.zybuluo.com/ysner/note/1298148

    题面

    字符串树本质上还是一棵树,即(N)个节点(N-1)条边的连通无向无环图,节点
    (1)(N)编号。与普通的树不同的是,树上的每条边都对应了一个字符串。萌萌
    (JYY)在树下玩的时候,萌萌决定考一考(JYY)。每次萌萌都写出一个字符串(S)
    两个节点(U,V),需要(JYY)立即回答(U)(V)之间的最短路径(即之间边数最少的
    路径。由于给定的是一棵树,这样的路径是唯一的)上有多少个字符串以为前
    缀。

    • (n,Qleq10^5)

    解析

    维护树上距离,我能想到的也只有树链剖分了。
    树链剖分维护树上距离,实际上是通过每个点到根节点的距离来进行的。

    那么这题也一样。
    维护一下每个点到根节点的字符串。
    又因为求的是前缀,可以用(Tire)树维护。
    注意到各节点字符串是有重复的。为了节省空间,可以把(Tire)树可持久化。
    然后就完事了。

    其实我一开始做这题时不知道怎么把字符串作为边权。。。

    #include<iostream>
    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #define ll long long
    #define re register
    #define il inline
    #define ls x<<1
    #define rs x<<1|1
    #define fp(i,a,b) for(re int i=a;i<=b;i++)
    #define fq(i,a,b) for(re int i=a;i>=b;i--)
    using namespace std;
    const int N=1e5+100;
    int n,q,h[N],cnt,sz[N],son[N],f[N],top[N],d[N],rt[N*100],tot;
    struct Tire{int son[26],w;}t[N*60];
    struct Edge{int to,nxt;char *s;}e[N<<1];
    il void add(re int u,re int v,re char *s){e[++cnt]=(Edge){v,h[u],s};h[u]=cnt;}
    char op[N][15];
    il ll gi()
    {
      re ll x=0,t=1;
      re char ch=getchar();
      while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
      if(ch=='-') t=-1,ch=getchar();
      while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
      return x*t;
    }
    il void Insert(re int &u,re char *s,re int x,re int n)
    {
      t[++tot]=t[u];u=tot;++t[u].w;
      if(x>n) return;
      Insert(t[u].son[s[x]-'a'],s,x+1,n);
    }
    il ll Query(re int u,re char *s,re int n)
    {
      fp(i,1,n) u=t[u].son[s[i]-'a'];
      return t[u].w;
    }
    il void dfs1(re int u,re int fa)
    {
      f[u]=fa;sz[u]=1;d[u]=d[fa]+1;
      for(re int i=h[u];i+1;i=e[i].nxt)
        {
          re int v=e[i].to;
          if(v==fa) continue;
          Insert(rt[v]=rt[u],e[i].s,1,strlen(e[i].s+1));
          dfs1(v,u);
          sz[u]+=sz[v];
          if(sz[v]>sz[son[u]]) son[u]=v;
        }
    }
    il void dfs2(re int u,re int up)
    {
      top[u]=up;
      if(son[u]) dfs2(son[u],up);
      for(re int i=h[u];i+1;i=e[i].nxt)
        {
          re int v=e[i].to;
          if(v==f[u]||v==son[u]) continue;
          dfs2(v,v);
        }
    }
    il int getLCA(re int u,re int v)
    {
      while(top[u]^top[v])
        {
          if(d[top[u]]<d[top[v]]) swap(u,v);
          u=f[top[u]];
        }
      return d[u]<d[v]?u:v;
    }
    int main()
    {
      memset(h,-1,sizeof(h));
      n=gi();
      fp(i,1,n-1)
        {
          re int u=gi(),v=gi();scanf("%s",op[i]+1);
          add(u,v,op[i]);add(v,u,op[i]);
        }
      dfs1(1,0);dfs2(1,1);
      q=gi();
      while(q--)
        {
          re int u=gi(),v=gi(),lca=getLCA(u,v);scanf("%s",op[0]+1);
          re int len=strlen(op[0]+1);
          printf("%lld
    ",Query(rt[u],op[0],len)+Query(rt[v],op[0],len)-2*Query(rt[lca],op[0],len));
        }
      return 0;
    }
    
  • 相关阅读:
    HDU 5273 Dylans loves sequence 暴力递推
    HDU 5285 wyh2000 and pupil 判二分图+贪心
    HDU 5281 Senior's Gun 贪心
    HDU 5651 xiaoxin juju needs help 逆元
    HDU 5646 DZY Loves Partition
    HDU 5366 The mook jong
    HDU 5391Z ball in Tina Town 数论
    HDU 5418 Victor and World 允许多次经过的TSP
    HDU 5642 King's Order dp
    抽屉原理
  • 原文地址:https://www.cnblogs.com/yanshannan/p/9727280.html
Copyright © 2011-2022 走看看