打击目标

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);
	}
}
posted @ 2018-10-07 20:31  yoyoball  阅读(174)  评论(0编辑  收藏  举报