题意:给定一个不超过10000个节点的树,每个节点都有一个小写字母。问是在树中是否存一条路径所构成的字符串为S。
分析:通过点分治能够快速得到所有路径,用哈希处理一下字符串的前缀后缀,在点分治是判断一下,就行啦。这题关键在于是否熟练使用点分治,会拉这题也就会做啦。(听说DFS加减支也能在正解的时间范围内通过)
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int N=10100;
const int INF=0x3f3f3f3f;
struct edge
{
int to,next;
} e[N*2];
int head[N],nu;
ULL base=7,bit[N],ch[N],s[N],pre[N],pos[N];
char ss[N],chh[N];
int vis1[N],vis2[N],len,lens,sum[N],maxs[N],S,maxx,root,n,times;
bool ans,vis[N];
void add(int from,int to)
{
e[nu].to=to;
e[nu].next=head[from];
head[from]=nu++;
}
void init()
{
nu=0;
times=1;
ans=false;
memset(vis1,0,sizeof(vis1));
memset(vis2,0,sizeof(vis2));
memset(head,-1,sizeof(head));
memset(vis,false,sizeof(vis));
}
void getroot(int x,int fa)
{
sum[x]=1;
maxs[x]=0;
for(int i=head[x]; i+1; i=e[i].next)
{
int y=e[i].to;
if(y==fa||vis[y])continue;
getroot(y,x);
sum[x]+=sum[y];
maxs[x]=max(maxs[x],sum[y]);
}
maxs[x]=max(maxs[x],S-sum[x]);
if(maxs[x]<maxx)
{
maxx=maxs[x];
root=x;
}
}
void dfs1(int x,int fa,ULL w,int cur)
{
if(cur>len||ans)return ;
w=w*base+s[x];
if(w==pre[cur]&&vis2[len-cur+1]==times)
{
ans=true;
return ;
}
if(w==pos[cur]&&vis1[len-cur+1]==times)
{
ans=true;
return ;
}
for(int i=head[x]; i+1; i=e[i].next)
{
int y=e[i].to;
if(y==fa||vis[y])continue;
dfs1(y,x,w,cur+1);
}
}
void dfs2(int x,int fa,ULL w,int cur)
{
if(cur>len)return;
w=w*base+s[x];
if(w==pre[cur])vis1[cur]=times;
if(w==pos[cur])vis2[cur]=times;
for(int i=head[x]; i+1; i=e[i].next)
{
int y=e[i].to;
if(y==fa||vis[y])continue;
dfs2(y,x,w,cur+1);
}
}
void divtree(int x,int fa)
{
if(ans)return;
vis[x]=true;
times++;
ULL w=s[x];
if(w==pre[1])vis1[1]=times;
if(w==pos[1])vis2[1]=times;
for(int i=head[x]; i+1; i=e[i].next)
{
int y=e[i].to;
if(y==fa||vis[y])continue;
dfs1(y,x,w,2);
if(ans)return ;
dfs2(y,x,w,2);
}
for(int i=head[x]; i+1; i=e[i].next)
{
int y=e[i].to;
if(y==fa||vis[y]||sum[y]<len)continue;
maxx=INF;
S=sum[y];
getroot(y,x);
divtree(root,x);
}
}
int main()
{
int x,y,TA,cas=1;
bit[1]=1;
for(int i=2; i<N; i++)bit[i]=bit[i-1]*base;
scanf("%d",&TA);
while(TA--)
{
init();
scanf("%d",&n);
for(int i=1; i<n; i++)
{
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
scanf(" %s",ss+1);
for(int i=1; i<=n; i++)s[i]=(ULL)ss[i];
scanf(" %s",chh+1);
len=strlen(chh+1);
for(int i=1; i<=len; i++)ch[i]=(ULL)chh[i];
if(len==1)
for(int i=1; i<=n; i++)if(s[i]==ch[1])
{
ans=true;
break;
}
if(!ans)
{
for(int i=1; i<=len; i++)pre[i]=pre[i-1]+ch[i]*bit[i];
for(int i=1; i<=len; i++)pos[i]=pos[i-1]+ch[len-i+1]*bit[i];
S=n;
maxx=INF;
getroot(1,-1);
divtree(root,-1);
}
if(ans)
printf("Case #%d: Find\n",cas++);
else
printf("Case #%d: Impossible\n",cas++);
}
}