@ysner
2018-09-29T16:48:06.000000Z
字数 2114
阅读 2690
树链剖分 可持久化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\n",Query(rt[u],op[0],len)+Query(rt[v],op[0],len)-2*Query(rt[lca],op[0],len));}return 0;}
