Jzoj4061 字符串树

给一个树,每条边上面有一个字符串,每次询问两个节点路径上的字符串中有多少以给定的一个字符串为前缀

显然是一个十分简单的题目,当时想多了打了树剖+Trie合并

后来才意识到可以用差分+可持久化trie,过于愚蠢了。。。。。

其实solution给了另一种解法,将所有字符串排序,哈希求lcp,让后存在一个数组里面,让后就可以用主席树了

反正这题比较简单

#pragma GCC opitmize("O3")
#pragma G++ opitmize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 100010
using namespace std;
struct edge{ int v,nt; } G[200010]; 
struct trie{ int c,s[26]; } s[2000010];
char c[200010][11],o[11];
int n,m,cnt=0,tot=0,h[N],d[N],f[N],sz[N],son[N],top[N],w[N];
inline void insert(int r1,int& r2,char* t){
	if(!r2) r2=++tot; s[r2].c=s[r1].c+1;
	if(*t){
		for(int i=0;i<26;++i) if(i+'a'!=*t) s[r2].s[i]=s[r1].s[i];
		insert(s[r1].s[*t-'a'],s[r2].s[*t-'a'],t+1);
	}	
}
inline int count(int r,char* t){
	for(;r&&*t;++t) r=s[r].s[*t-'a'];
	return s[r].c;
}
inline void adj(int x,int y,char* t){
	G[++cnt]=(edge){y,h[x]}; h[x]=cnt; 
	for(int i=0;*t;++t,++i) c[cnt][i]=*t;
}
void dfs(int x,int p){
	d[x]=d[p]+1; f[x]=p; sz[x]=1;
	for(int v,i=h[x];i;i=G[i].nt)
		if((v=G[i].v)!=p){
			insert(w[x],w[v],c[i]);
			dfs(v,x); sz[x]+=sz[v];
			if(sz[v]>sz[son[x]]) son[x]=v;
		}
}
void dgs(int x,int p){
	top[x]=p;
	if(son[x]) dgs(son[x],p);
	for(int v,i=h[x];i;i=G[i].nt)
		if(!top[v=G[i].v]) dgs(v,v);
}
inline int gLca(int x,int y,char* o){
	int v=count(w[x],o)+count(w[y],o);
	for(;top[x]!=top[y];y=f[top[y]])
		if(d[top[x]]>d[top[y]]) swap(x,y);
	if(d[x]>d[y]) swap(x,y);
	return v-2*count(w[x],o);
}
int main(){
	freopen("strings.in","r",stdin);
	freopen("strings.out","w",stdout);
	scanf("%d",&n);
	for(int x,y,i=1;i<n;++i){
		scanf("%d%d%s",&x,&y,o);
		adj(x,y,o); adj(y,x,o);
	}
	dfs(1,0); dgs(1,1); scanf("%d",&m);
	for(int x,y;m--;){
		scanf("%d%d%s",&x,&y,&o);
		printf("%d\n",gLca(x,y,o));
	}
}

posted @ 2017-12-04 20:42  扩展的灰(Extended_Ash)  阅读(98)  评论(0编辑  收藏  举报