【JSOI2015】字符串树

来源:互联网 发布:cbox网络电视官方 编辑:程序博客网 时间:2024/05/22 10:36

这里写图片描述

题解

由于字符串长度不超过10,所以trie的深度就不超过10。
对于一条边u,v,s
那么我们将v从u上继承信息,然后对于v的trie树,插入s这个串,将路径上每一个点的权值都+1
不过我们不可能对每一个点都开一个trie,
我们会发现每一次加入一条边,只有字符串长度个点发生改变,
所以,就用可持久化trie。

code

#include<iostream>#include<cmath>#include<cstring>#include<cstdio>#include<algorithm>#define N 100003using namespace std;struct arr{    int x,son[26];}t[10*N];int a[N*2],b[N],next[N*2],v[N*2],tot,len[N],f[N][20];char s[N][20],st[20];int n,m,x,y,ans,l,root[N],deep[N];void ins(int x,int y,int z){    next[++tot]=b[x];    a[tot]=y;    v[tot]=z;    b[x]=tot;}void in(int x,int fa,int z){    root[x]=++tot;    fa=root[fa];    for(int i=0;i<len[z];i++)    {        t[tot]=t[fa];        t[tot].x++;        t[tot].son[s[z][i]-'a']=++tot;        fa=t[fa].son[s[z][i]-'a'];    }    t[tot].x++;}void dfs(int x,int fa){    for(int i=b[x];i;i=next[i])        if(a[i]!=fa)        {            in(a[i],x,v[i]);            f[a[i]][0]=x;            deep[a[i]]=deep[x]+1;            dfs(a[i],x);        }}int lca(int x,int y){    if(deep[x]<deep[y])swap(x,y);    for(int j=16;j>=0;j--)        if(deep[f[x][j]]>=deep[y])x=f[x][j];    for(int j=16;j>=0;j--)        if(f[x][j]!=f[y][j])x=f[x][j],y=f[y][j];    if(x==y)return x;else return f[x][0];}int find(int x,int i){    if(i==l)return t[x].x;    return find(t[x].son[st[i]-'a'],i+1);}int main(){    freopen("strings.in","r",stdin);    freopen("strings.out","w",stdout);    scanf("%d",&n);    for(int i=1;i<n;i++)    {        scanf("%d%d%s",&x,&y,&s[i]);        ins(x,y,i);        ins(y,x,i);        len[i]=strlen(s[i]);    }    deep[1]=tot=root[1]=1;    dfs(1,0);    for(int j=1;j<17;j++)        for(int i=1;i<=n;i++)            f[i][j]=f[f[i][j-1]][j-1];    scanf("%d",&m);    for(int i=1;i<=m;i++)    {        scanf("%d%d%s",&x,&y,&st);        l=strlen(st);        printf("%d\n",find(root[x],0)+find(root[y],0)-2*find(root[lca(x,y)],0));    }}
0 0