• [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;
    }
    
  • 相关阅读:
    vue 中 vue-router、transition、keep-alive 怎么结合使用?
    vue 对列表数组删除和增加
    eclipse如何快速查找某个类
    在 eclipse 中设置每行的字数
    如何查看某个端口被谁占用
    sql只修改第一二行数据
    android真机自动化测试
    appium自动化测试中获取toast消息的解决方法【转】
    eclipse下python的selenium自动化环境的搭建
    Xpath用法官方手册
  • 原文地址:https://www.cnblogs.com/yanshannan/p/9727280.html
Copyright © 2020-2023  润新知