这是一道裸的可持久化trie树。这个方法就不多说了,详见“初探主席树”及“cout on a tree”。
代码:
#include<cstdio> #include<cstring> #include<algorithm> #define N 100010 using namespace std; int n,u,v,cnt,l,q; int edgenum,vet[2*N],next[2*N],head[2*N],root[N]; int f[N],d[N],num[N],son[N],top[N]; struct node{int sum,son[30];}tr[10*N]; char str[15],s[N][15]; void add(int u,int v) { edgenum++; vet[edgenum]=v; next[edgenum]=head[u]; head[u]=edgenum; } void dfs(int u,int fa,int dep) { f[u]=fa; d[u]=dep; num[u]=1; int maxnum=0; for (int e=head[u];e;e=next[e]) { int v=vet[e]; if (v!=fa) { dfs(v,u,dep+1); num[u]+=num[v]; if (num[v]>maxnum){maxnum=num[v];son[u]=v;} } } } void dfs(int u,int number) { top[u]=number; if (!son[u]) return; dfs(son[u],number); for (int e=head[u];e;e=next[e]) { int v=vet[e]; if (v!=f[u]&&v!=son[u]) dfs(v,v); } } int getlca(int u,int v) { while (top[u]!=top[v]) { if (d[top[u]]<d[top[v]]) swap(u,v); u=f[top[u]]; } if (d[u]<d[v]) return u;else return v; } void change(int &p,int k,int dep) { tr[++cnt]=tr[p];p=cnt;tr[p].sum++; if (dep==strlen(s[k])) return; change(tr[p].son[s[k][dep]-'a'],k,dep+1); } int ask(int p,int dep) { if (p==0&&dep) return 0; if (dep==l) return tr[p].sum; return ask(tr[p].son[str[dep]-'a'],dep+1); } void dfs1(int u,int e) { if (u!=1){root[u]=root[f[u]];change(root[u],(e+1)>>1,0);} for (int e=head[u];e;e=next[e]) { int v=vet[e]; if (v!=f[u]) dfs1(v,e); } } int main() { scanf("%d",&n); for (int i=1;i<n;i++) { scanf("%d%d%s",&u,&v,s[i]); add(u,v);add(v,u); } dfs(1,0,1); dfs(1,1); dfs1(1,0); scanf("%d",&q); while (q--) { scanf("%d%d%s",&u,&v,str); l=strlen(str); printf("%d\n",ask(root[u],0)+ask(root[v],0)-2*ask(root[getlca(u,v)],0)); } }
还有一种我在练习赛上自己yy的一种方法。然而,有些复杂(我是有自知之明的),文字解释起来非常复杂,代码放着,有兴趣的人可以自己研究一下。
代码:
#include<cstdio> #include<cstring> #include<algorithm> #define N 100010 using namespace std; typedef long long ll; int n,q,cnt,l; int edgenum,Edgenum,vet[2*N],next[2*N],head[2*N],Vet[10*N],Next[10*N],Head[10*N],x[N],y[N],a[N],b[N],lca[N]; ll dis[2*N],Ask[10*N],P[10*N],p[10*N],ans[N],mi[20],w[N],c[N],d[N]; int f[N],de[N],num[N],son[N],top[N],tr[10*N]; char s[20]; void add(int u,int v,ll w) { edgenum++; vet[edgenum]=v; next[edgenum]=head[u]; head[u]=edgenum; dis[edgenum]=w; } void dfs(int u,int fa,int dep) { f[u]=fa; de[u]=dep; num[u]=1; int maxnum=0; for (int e=head[u];e;e=next[e]) { int v=vet[e]; if (v!=fa) { dfs(v,u,dep+1); num[u]+=num[v]; if (num[v]>maxnum){maxnum=num[v];son[u]=v;} } } } void dfs(int u,int number) { top[u]=number; if (!son[u]) return; dfs(son[u],number); for (int e=head[u];e;e=next[e]) { int v=vet[e]; if (v!=f[u]&&v!=son[u]) dfs(v,v); } } int getlca(int u,int v) { while (top[u]!=top[v]) { if (de[top[u]]<de[top[v]]) swap(u,v); u=f[top[u]]; } if (de[u]<de[v]) return u;else return v; } void Add(int u,int v,ll w,ll opt) { Edgenum++; Vet[Edgenum]=v; Next[Edgenum]=Head[u]; Head[u]=Edgenum; Ask[Edgenum]=w; P[Edgenum]=opt; } int asksum(ll x) { int ans=0; while (x) { ans+=tr[x]; x-=((x)&(-x)); } return ans; } void tradd(ll x,int val) { while (x<=cnt) { tr[x]+=val; x+=((x)&(-x)); } } void dfs(int u) { for (int e=Head[u];e;e=Next[e]) { int v=Vet[e]; ans[v]+=(ll)asksum(Ask[e])*P[e]; } for (int e=head[u];e;e=next[e]) { int v=vet[e]; if (v!=f[u]) { tradd(dis[e],1); dfs(v); tradd(dis[e],-1); } } } int main() { freopen("strings.in","r",stdin); freopen("strings.out","w",stdout); scanf("%d",&n); mi[0]=1; for (int i=1;i<=10;i++) mi[i]=mi[i-1]*31; for (int i=1;i<n;i++) { scanf("%d%d%s",&x[i],&y[i],s); l=strlen(s); w[i]=0; for (int j=0;j<l;j++) w[i]=w[i]*31+s[j]-'a'+1; w[i]=w[i]*mi[10-l]; p[++cnt]=(ll)w[i]; add(x[i],y[i],w[i]);add(y[i],x[i],w[i]); } dfs(1,0,1); dfs(1,1); scanf("%d",&q); for (int i=1;i<=q;i++) { scanf("%d%d%s",&a[i],&b[i],s); lca[i]=getlca(a[i],b[i]); c[i]=0; l=strlen(s); for (int j=0;j<l;j++) c[i]=c[i]*31+s[j]-'a'+1; c[i]=c[i]*mi[10-l]; d[i]=c[i]+(mi[10-l]-1)/30*('z'-'a'+1); p[++cnt]=(ll)c[i]-1; p[++cnt]=(ll)d[i]; Add(a[i],i,d[i],1); Add(b[i],i,d[i],1); Add(lca[i],i,d[i],-2); Add(a[i],i,c[i]-1,-1); Add(b[i],i,c[i]-1,-1); Add(lca[i],i,c[i]-1,2); } sort(p+1,p+cnt+1); cnt=unique(p+1,p+cnt+1)-p-1; for (int i=1;i<=edgenum;i++) dis[i]=lower_bound(p+1,p+cnt+1,dis[i])-p; for (int i=1;i<=Edgenum;i++) Ask[i]=lower_bound(p+1,p+cnt+1,Ask[i])-p; dfs(1); for (int i=1;i<=q;i++) printf("%lld\n",ans[i]); }