bzoj4477: [Jsoi2015]字符串树(可持久化trie树+lca)

dfs时在父亲的基础上加一个字符串,即它和父亲的连边所代表字符串。//一定要记得把父亲的信息完整的传递啊。

利用树上差分的思想,u到v最短路上有多少字符串以s为前缀 = 根到u的路径上有多少字符串以s为前缀+根到v的路径上有多少字符串以s为前缀 - 2 * 根到lca(u,v)的路径上有多少字符串以s为前缀

其实是到板子题,把板子背好就好。//注意数组开的大小啊,我sum开小了最开始一直re.

#include
#include
#include
using namespace std;
int n,tp,nex[200005],toh[200005],tov[200005],h[200005];
int dep[200005], fa[200005], top[200005], siz[200005], son[200005], root[200005];
int tr[1000005][27], cnt, sum[27000005];
char s[100005][15], s1[15];
void read(int &x)
{
	int f = 0; x = 0; char c = getchar();
	while(c < '0' || c > '9'){if(c == '-') f = 1; c = getchar();} 
	while(c >= '0' && c <= '9'){x = x * 10 + c - '0'; c = getchar();}
	 if(f) x = -x;
}
void add(int x,int y, int i)   
{tp++; nex[tp] = h[x]; toh[tp] = i; tov[tp] = y; h[x] = tp;} 
int insert(int nd,int x)
{
	int len = strlen(s[x]);  int nd1 = ++ cnt; int he = nd1;
	for(int i = 0; i < len; i++)
    {
    	int ha = s[x][i] - 'a';    
    	for(int j = 0; j <= 25; j++) tr[nd1][j] = tr[nd][j];
		 tr[nd1][ha] = ++ cnt;
         nd1 = tr[nd1][ha];nd = tr[nd][ha];
         sum[nd1] += sum[nd]; sum[nd1] += 1; 
     
	}
	return he;
}
void dfs(int x,int f)
{
	fa[x] = f; siz[x] = 1;
	for(int i = h[x]; i; i = nex[i])
	{
		int v = tov[i]; if(v == f) continue;
		root[v] = insert(root[x],toh[i]);
		dep[v] = dep[x] + 1; dfs(v,x); siz[x] += siz[v];
	     if(siz[v] > siz[son[x]]) son[x] = v;
	}
}
void dfs1(int x,int f)
{
	top[x] = f; if(son[x]) dfs1(son[x],f);
	for(int i = h[x]; i; i = nex[i])
	{
		int v = tov[i]; if(v == fa[x] || v == son[x]) continue;
		dfs1(v,v);
	}
}
int lca(int x,int u)
{
	while(top[x] != top[u])
	{
		if(dep[top[u]] > dep[top[x]] ) swap(x,u);  x = fa[top[x]];
	}
	return dep[x] > dep[u] ? u : x;
}
int qurey(int x,char ss[15])
{
	int nd = x;
	for(int i = 0; i < strlen(ss); i++) 
	{int ha = ss[i] - 'a'; nd = tr[nd][ha];} 
	return sum[nd];
}
int main()
{
   read(n);
  for(int i = 1; i < n; i++)
  {int x,y; read(x); read(y); scanf("%s",s[i]); add(x, y, i); add(y, x, i);}
  dfs(1,1);dfs1(1,1);
  int q ;read(q);
  for(int i = 1; i <= q; i++)
  {
  	int x,y; read(x); read(y); scanf("%s",s1);
  	int l = lca(x,y);
  	int ans1 = qurey(root[x],s1);
    int ans2 = qurey(root[y],s1);
    int ans3 = qurey(root[l],s1);
    printf("%d\n",ans1 + ans2 - 2 * ans3);
  }
  return 0;
}

 

 

 

 

你可能感兴趣的:(树上差分,主席树,trie树)