题目描述
传送门
题目大意:给出一个n个节点的树,每个节点上有一个大写字母,给出一个模式串,求有多少路径是由模式串重复若干次得到的。
题解
hash+点分治。 对于每个点依次加入他的每个儿子的子树,然后计算当前儿子的子树与已经处理过的儿子的子树能形成多少合法串。 对于路径上行和下行都要考虑,用hash判断路径是否是模式串的前后缀。 注意细节。 时间复杂度应该是
O(Tnlogn)
代码
using namespace std;
int n,
m,T,n1,root,point[N],nxt[N
*2],v[N
*2],tot,size[N],f[N],sz,sz1;
int st[N],st1[N],len[N],cnt[N],cnt1[N];
ull mi[N],a[N],a1[N],b[N],c[N],val[N],sum[N],sum1[N];
LL ans;
bool vis[N];
char
s[N];
int read()
{
char ch = getchar();
for ( ; ch >
'9' || ch <
'0'; ch = getchar());
int tmp =
0;
for ( ;
'0' <= ch && ch <=
'9'; ch = getchar())
tmp = tmp *
10 +
int(ch) -
48;
return tmp;
}
void add(
int x,
int y)
{
tot++; nxt[tot]=point[
x]; point[
x]=tot; v[tot]=
y;
tot++; nxt[tot]=point[
y]; point[
y]=tot; v[tot]=
x;
}
void get_root(
int x,
int fa)
{
size[
x]=
1; f[
x]=
0;
for (
int i=point[
x];i;i=nxt[i]) {
if (v[i]==fa||vis[v[i]])
continue;
get_root(v[i],
x);
f[
x]=max(f[
x],size[v[i]]);
size[
x]+=size[v[i]];
}
f[
x]=max(f[
x],n1-size[
x]);
if (f[
x]<f[root]) root=
x;
}
void get_deep(
int x,
int fa)
{
if (b[len[
x]]==sum[
x]&&val[
x]==a[
1]) st[++sz]=
x;
for (
int i=point[
x];i;i=nxt[i]){
if (vis[v[i]]||v[i]==fa)
continue;
sum[v[i]]=sum[
x]
*p+val[v[i]];
len[v[i]]=len[
x]+
1;
get_deep(v[i],
x);
}
}
void get_deep1(
int x,
int fa)
{
if (c[len[
x]]==sum1[
x]&&val[
x]==a1[
1]) st1[++sz1]=
x;
for (
int i=point[
x];i;i=nxt[i]) {
if(vis[v[i]]||v[i]==fa)
continue;
sum1[v[i]]=sum1[
x]
*p+val[v[i]];
get_deep1(v[i],
x);
}
}
void calc(
int x)
{
for (
int i=
0;i<=
m;i++) cnt[i]=
0,cnt1[i]=
0;
if (a[
1]==val[
x])cnt[
1]=
1;
if (a[
m]==val[
x])cnt1[
1]=
1;
if (
m==
1) ans+=cnt[
1];
for (
int i=point[
x];i;i=nxt[i]) {
if (vis[v[i]])
continue;
sz=
0; len[v[i]]=
1; sum[v[i]]=val[v[i]];
get_deep(v[i],
x);
for (
int j=
1;j<=sz;j++) {
int t=st[j];
int pos=
m-(len[t]-
1)
%m-
1;
if (
pos==
0)
pos+=
m;
ans+=(LL)cnt1[
pos];
}
sz1=
0; sum1[v[i]]=val[v[i]];
get_deep1(v[i],
x);
for (
int j=
1;j<=sz1;j++) {
int t=st1[j];
int pos=
m-(len[t]-
1)
%m-
1;
if (
pos==
0)
pos+=
m;
ans+=(LL)cnt[
pos];
}
for (
int j=
1;j<=sz;j++) {
int t=st[j];
int pos=(len[t])
%m+
1;
if (val[
x]==a[
pos]) cnt[
pos]++;
}
for (
int j=
1;j<=sz1;j++) {
int t=st1[j];
int pos=(len[t])
%m+
1;
if (val[
x]==a1[
pos]) cnt1[
pos]++;
}
}
}
void solve(
int x)
{
calc(
x); vis[
x]=
1;
for (
int i=point[
x];i;i=nxt[i]) {
if (vis[v[i]])
continue;
n1=size[v[i]]; root=
0;
if (n1<
m)
continue;
get_root(v[i],
x);
solve(root);
}
}
int main()
{
freopen(
"a.in",
"r",stdin);
// freopen(
"my.out",
"w",stdout);
T=
read(); mi[
0]=
1;
for (
int i=
1;i<=
1000000;i++) mi[i]=mi[i-
1]
*p;
while (T--) {
n=
read();
m=
read(); tot=
0; ans=
0;
memset(point,
0,sizeof(point));
scanf(
"%s",
s+
1);
for (
int i=
1;i<=n;i++) val[i]=
s[i]-
'A'+
1;
for (
int i=
1;i<n;i++) {
int x,
y;
x=
read();
y=
read();
add(
x,
y);
}
scanf(
"%s",
s+
1);
for (
int i=
1;i<=max(n,
m);i++) a[i]=
s[(i-
1)
%m+
1]-
'A'+
1;
for (
int i=
1;i<=max(n,
m);i++) b[i]=b[i-
1]+a[i]
*mi[i-
1];
for (
int i=
1;i<=
m;i++) a1[
m-i+
1]=a[i];
for (
int i=
1;i<=max(n,
m);i++) a1[i]=a1[(i-
1)
%m+
1];
for (
int i=
1;i<=max(n,
m);i++) c[i]=c[i-
1]+a1[i]
*mi[i-
1];
memset(vis,
0,sizeof(vis));
f[
0]=inf; root=
0; n1=n;
get_root(
1,
0);
solve(root);
printf(
"%lld\n",ans);
}
}
转载请注明原文地址: https://ju.6miu.com/read-669772.html