Description
Input
Output
Sample Input
3 0
xyz xy x
1 2
2
1 3 xyz
2 3 zzzzxy
Sample Output
3
2
Data Constraint
题解
这一题在比赛的时候我已经想到了和题解基本一样的做法,然而因为不会树剖(雾,所以只打了50point,结果数据超级水,要不是开小了数组就AC了QvQ
下午赶紧学习了一下树剖,然后发现是一个超级简单的东西,就是维护出每一个点对应的重链的上面的顶点是什么,然后看哪边深就跳哪边就好了
那么这一题怎么做呢?
收先看到多串匹配条件反射的就想到了SA和AC自动机
看了一下发现就是一个AC自动机
某一个串经过的自动机中某一节点沿着fail能跳到的就是它的子串
那么我们不妨对自动机中的每一个点挂一个可持久化线段树,然后沿着fail边不断的更新就好了
询问的话因为树剖了一下所以只有log段,复杂度应该是两个log的
贴代码
打的不是很优美。。。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fo1(i,b,a) for(i=b;i>=a;i--)
#define max(x,y) ((x)>(y)?(x):(y))
using namespace std;
const int maxn=1e5+5;
int tree[maxn*10][27],fail[maxn*10],h[maxn*10];
int tr[maxn*50][3];
int ff[maxn][18];
int cc[maxn*10],de[maxn],dep[maxn*10];
int fi[maxn],ne[maxn*2],dui[maxn*2],qc[maxn],siz[maxn];
int fi1[maxn*3],ne1[maxn*5],dui1[maxn*5],qc1[maxn*3];
int fa[maxn],dfn[maxn],top[maxn],go[maxn],root[maxn*10];
bool bq;
int i,j,k,l,m,n,x,y,z,o,ans,now,q,xz,zo,zz,cz,mx,xx,yy,p,xc;
char s[maxn];
void add(int x,int y){
if (fi[x]==0) fi[x]=++mx; else ne[qc[x]]=++mx;
dui[mx]=y; qc[x]=mx;
}
void add1(int x,int y){
if (fi1[x]==0) fi1[x]=++mx; else ne1[qc1[x]]=++mx;
dui1[mx]=y; qc1[x]=mx;
}
void ge_a(){
k=0;
fo(i,1,26) if (tree[0][i]) h[++k]=tree[0][i];
i=k; j=0;
while (i>j){
j++; x=h[j];
fo(k,1,26) if (tree[x][k]){
now=fail[x];
while (tree[now][k]==0 && now>0) now=fail[now];
if (tree[now][k]) now=tree[now][k];
fail[tree[x][k]]=now;
h[++i]=tree[x][k];
}
}
}
void ge_ff(){
fo(j,1,16)
fo(i,1,n) ff[i][j]=ff[ff[i][j-1]][j-1];
}
int lca(int x,int y){
if (de[x]<de[y]){
int z=x; x=y; y=z;
}
fo1(i,16,0) if (de[x]-(1<<i)>=de[y]) x=ff[x][i];
fo1(i,16,0) if (ff[x][i]!=ff[y][i]){
x=ff[x][i]; y=ff[y][i];
}
if (x!=y) x=ff[x][0];
return x;
}
void dfs(int x){
int i=fi[x]; siz[x]=1;
while (i){
de[dui[i]]=de[x]+1;
dfs(dui[i]);
siz[x]+=siz[dui[i]];
if (siz[dui[i]]>siz[go[x]]) go[x]=dui[i];
i=ne[i];
}
}
void dfss(int x){
dfn[x]=++now;
top[go[x]]=top[x];
if (go[x]) dfss(go[x]);
int i=fi[x];
while (i){
if (dui[i]==go[x]){
i=ne[i]; continue;
}
top[dui[i]]=dui[i];
dfss(dui[i]);
i=ne[i];
}
}
void maketree(int v,int s1,int s2,int l,int r){
tr[++p][0]=tr[v][0]; tr[p][1]=tr[v][1]; tr[p][2]=tr[v][2];
int q=p;
if (l==r){
tr[p][2]=s2; return;
}
int mid=(l+r)/2;
if (s1<=mid){
tr[p][0]=p+1;
maketree(tr[v][0],s1,s2,l,mid);
} else{
tr[p][1]=p+1;
maketree(tr[v][1],s1,s2,mid+1,r);
}
tr[q][2]=max(tr[tr[q][0]][2],tr[tr[q][1]][2]);
}
void wor(int x){
if (! root[fail[x]] && fail[x]) wor(fail[x]);
if (fi1[x]){
int pp=fi1[x];
root[x]=p+1;
maketree(root[fail[x]],dfn[dui1[pp]],dep[x],1,n); pp=ne1[pp];
while (pp){
int qq=p+1;
maketree(root[x],dfn[dui1[pp]],dep[x],1,n);
root[x]=qq;
pp=ne1[pp];
}
}
else root[x]=root[fail[x]];
}
void find(int v,int l,int r,int x,int y){
if (l==x && r==y) ans=max(ans,tr[v][2]); else{
int mid=(l+r)/2;
if (y<=mid) find(tr[v][0],l,mid,x,y); else
if (x>mid) find(tr[v][1],mid+1,r,x,y); else{
find(tr[v][0],l,mid,x,mid);
find(tr[v][1],mid+1,r,mid+1,y);
}
}
}
void tur(int q){
xx=x; yy=y;
while (top[xx]!=top[yy]){
if (de[top[xx]]<de[top[yy]]){
find(root[q],1,n,dfn[top[yy]],dfn[yy]);
yy=fa[top[yy]];
} else{
find(root[q],1,n,dfn[top[xx]],dfn[xx]);
xx=fa[top[xx]];
}
}
if (dfn[xx]>dfn[yy]){
z=xx; xx=yy; yy=z;
}
find(root[q],1,n,dfn[xx],dfn[yy]);
}
int main(){
// freopen("t2.in","r",stdin);
// freopen("t2.out","w",stdout);
scanf("%d%d",&n,&o);
fo(i,1,n){
scanf("%s",s+1); l=strlen(s+1);
now=0;
fo(j,1,l){
x=s[j]-96;
if (tree[now][x]) now=tree[now][x]; else{
tree[now][x]=zo+1; dep[++zo]=dep[now]+1;
now=tree[now][x];
}
}
add1(now,i);
}
ge_a(); mx=0;
fo(i,2,n){
scanf("%d",&ff[i][0]); fa[i]=ff[i][0];
add(ff[i][0],i);
}
ge_ff();
now=0;
dfs(1); top[1]=1;
dfss(1); p=0;
fo(i,1,zo)
if (! root[i]) wor(i);
scanf("%d",&q); ans=0;
fo(xz,1,q){
scanf("%d%d",&x,&y);
if (o){
x^=ans; y^=ans;
} xx=x; yy=y;
z=lca(x,y);
now=0; scanf("%s",s+1); l=strlen(s+1); ans=0;
fo(i,1,l){
xc=s[i]-96;
while (now>0 && tree[now][xc]==0) now=fail[now];
if (tree[now][xc]) now=tree[now][xc];
tur(now);
}
printf("%d\n",ans);
}
return 0;
}