打击目标
Portal --> broken
Description
给你一棵有根树(\(1\)为根节点),每个节点有一个对应的字符串,现在给出若干询问,每次询问\(x\)到\(y\)路径上的点的字符串中,是给定串\(S\)的子串的字符串的最长长度
部分数据强制在线
数据范围:\(n<=10^5,\sum|w|<=10^5,1<=|m[i]|<=10\),其中\(w\)是每次询问中的\(S\)的长度,\(m[i]\)表示的是第\(i\)个节点对应的字符串
Solution
场上想了一下应该是。。什么ac自动机和线段树套在一起的树剖==
然后特别愚蠢地把ac自动机套在了线段树里面我也真是有勇气qwq然后这个洋溢着梦想气息的做法获得了\(50\)分的好成绩==
一种做法是一开始先对所有的\(m[i]\)建出ac自动机,建出fail树,然后。。再套一个主席树什么的,查询的时候边在fail树上面跑边在主席树里面查路径对应区间的最大值(大概是这样。。具体细节没有细想qwq)
然而实际上。。我们为什么一定要用ac自动机呢0.0
注意到\(m[i]\)很小,然后数据又对\(\sum|w|\)有限制,所以。。我们可以直接暴力枚举每次询问中\(S\)的长度\(<=10\)的子串,然后剩下的事情就是查路径上面是否有这个子串就好了==
具体实现的话我们可以先把所有的\(m[i]\)哈希一下,然后离散化一下,然后查的时候先lower_bound一下什么的就好了
mark:提醒自己不能写数据结构写傻了啊==数据范围还是很重要的。。对这种小的不正常的范围一定要足够敏感才行
代码大概长这个样子
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ull unsigned long long
using namespace std;
const int N=1e5+10,TOP=17,Hs=19260817;
struct xxx{
int y,nxt;
}a[N];
char s[N][15],S[N];
ull val[N],lis[N],pw[N],V[N];
int id[N];
int h[N],f[N][TOP+1],dep[N];
int n,m,tot,lastans,O,dfn_t;
namespace Seg{/*{{{*/
const int N=::N*20;
int ch[N][2],sum[N],rt[::N];
int n,tot;
void init(int _n){n=_n; tot=0;}
int newnode(int pre){
ch[++tot][0]=ch[pre][0]; ch[tot][1]=ch[pre][1]; sum[tot]=sum[pre];
return tot;
}
void _insert(int pre,int &x,int d,int lx,int rx){
x=newnode(pre);
++sum[x];
if (lx==rx) return;
int mid=lx+rx>>1;
if (d<=mid) _insert(ch[pre][0],ch[x][0],d,lx,mid);
else _insert(ch[pre][1],ch[x][1],d,mid+1,rx);
}
void insert(int pre,int x,int d){_insert(rt[pre],rt[x],d,1,n);}
int _query(int x,int y,int lca,int d,int lx,int rx){
if (lx==rx) return sum[x]+sum[y]-sum[lca]*2;
int mid=lx+rx>>1;
if (d<=mid) return _query(ch[x][0],ch[y][0],ch[lca][0],d,lx,mid);
else return _query(ch[x][1],ch[y][1],ch[lca][1],d,mid+1,rx);
}
int query(int x,int y,int lca,int d){return _query(rt[x],rt[y],rt[lca],d,1,n);}
}/*}}}*/
void add(int x,int y){a[++tot].y=y; a[tot].nxt=h[x]; h[x]=tot;}
void dfs(int fa,int x,int d){
int u;
dep[x]=d; f[x][0]=fa;
Seg::insert(fa,x,id[x]);
for (int i=1;i<=TOP;++i) f[x][i]=f[f[x][i-1]][i-1];
for (int i=h[x];i!=-1;i=a[i].nxt){
u=a[i].y;
dfs(x,u,d+1);
}
}
int get_lca(int x,int y){
if (dep[x]<dep[y]) swap(x,y);
for (int i=TOP;i>=0;--i)
if (dep[f[x][i]]>=dep[y]) x=f[x][i];
if (x==y) return x;
for (int i=TOP;i>=0;--i)
if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
return f[x][0];
}
void prework(){
int len;
lis[0]=0;
for (int i=1;i<=n;++i){
len=strlen(s[i]);
val[i]=0;
for (int j=0;j<len;++j) val[i]=val[i]*Hs+s[i][j]-'a'+1;
lis[++lis[0]]=val[i];
}
sort(lis+1,lis+1+lis[0]);
lis[0]=unique(lis+1,lis+1+lis[0])-lis-1;
for (int i=1;i<=n;++i)
id[i]=lower_bound(lis+1,lis+1+lis[0],val[i])-lis;
Seg::init(lis[0]);
pw[0]=1;
for (int i=1;i<=1e5;++i) pw[i]=pw[i-1]*Hs;
}
ull get_val(int l,int r){
return V[r]-V[l-1]*pw[r-l+1];
}
void solve(int x,int y){
int lca=get_lca(x,y),lenS=strlen(S);
int pos;
ull tmp;
lastans=0;
V[0]=S[0]-'a'+1;
for (int i=1;i<lenS;++i) V[i]=V[i-1]*Hs+S[i]-'a'+1;
for (int len=10;len>=0;--len){
for (int i=0;i+len-1<lenS;++i){
tmp=get_val(i,i+len-1);
pos=lower_bound(lis+1,lis+1+lis[0],tmp)-lis;
if (lis[pos]!=tmp) continue;
if (Seg::query(x,y,lca,pos)+(id[lca]==pos)){lastans=len;return;}
}
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
int x,y;
scanf("%d%d",&n,&O);
for (int i=1;i<=n;++i) scanf("%s",s[i]);
prework();
memset(h,-1,sizeof(h));
tot=0; lastans=0;
for (int i=2;i<=n;++i){
scanf("%d",&x);
add(x,i);
}
dfs(0,1,1);
scanf("%d",&m);
for (int i=1;i<=m;++i){
scanf("%d%d%s",&x,&y,S);
x^=lastans*O;
y^=lastans*O;
solve(x,y);
printf("%d\n",lastans);
}
}