Here
- 利用回文串,从左往右与从右往左的hash值相同来判断
- 从左往右,例:
- 从右往左,例:
- 由于在树上,考虑建两颗树,一颗根为最高位(up),一棵根为最低位(down)
- 考虑bccb(1,2,3,4)这个
- ,即bcc
- ,即b
- 所以设在树上两点
- (乘inv使x为最低位)
- ,swap(u,v)即可
- 为保证hash的正确性,采用双哈希,
import java.io.*;
import java.math.BigInteger;
import java.util.*;
//implements Runnable
public class Main {
static long md1=(long)1e9+7;
static long md2=(long)1e9+9;
static long Linf=Long.MAX_VALUE/2;
static int inf=Integer.MAX_VALUE/2;
static int N=200010;
static int n=0;
static int m=0;
static
class M{
long x,y;
public M(){};
public M(long u,long v){
x=u;y=v;
}
}
static M mul(M a,M b){
return new M(a.x*b.x%md1,a.y*b.y%md2);
}
static M add(M a,M b){
return new M((a.x+b.x)%md1,(a.y+b.y)%md2);
}
static M sub(M a,M b){
return new M((a.x-b.x+md1)%md1,(a.y-b.y+md2)%md2);
}
static M[] inv;
static M[] fac;
static M base=new M(29,131);
static long qm2(long a,long b,long md){
long res=1;
while(b>0){
if((b&1)==1)res=res*a%md;
a=a*a%md;
b>>=1;
}
return res;
}
static void getFac(){
fac[0]=new M(1,1);
up[0]=new M(0,0);
down[0]=new M(0,0);
for(int i=1;i<=n;++i){
fac[i]=mul(fac[i-1],base);
}
inv[n]=new M();
inv[n].x=qm2(fac[n].x,md1-2,md1);
inv[n].y=qm2(fac[n].y,md2-2,md2);
for(int i=n-1;i>=0;i--){
inv[i]=mul(inv[i+1],base);
}
}
static
class Edge{
int fr,to,nxt;
public Edge(int u,int v){
fr=u;to=v;
}
}
static Edge[] e;
static int[] head;
static int cnt=0;
static void addEdge(int fr,int to){
cnt++;
e[cnt]=new Edge(fr,to);
e[cnt].nxt=head[fr];
head[fr]=cnt;
}
static int[] fa;
static int[] son;
static int[] siz;
static int[] dep;
static int[] top;
static M[] down;
static M[] up;
static int[] a;
static void dfs1(int x,int f){
siz[x]=1;dep[x]=dep[f]+1;fa[x]=f;
up[x]=add(mul(up[f],base),new M(a[x],a[x]));
down[x]=add(down[f],mul(new M(a[x],a[x]),fac[dep[x]]));
for(int i=head[x];i>0;i=e[i].nxt){
int v=e[i].to;
if(v==f)continue;
dfs1(v,x);
siz[x]+=siz[v];
if(siz[son[x]]<siz[v])son[x]=v;
}
}
static void dfs2(int x,int tp){
top[x]=tp;
if(son[x]!=0)dfs2(son[x],tp);
for(int i=head[x];i>0;i=e[i].nxt){
int v=e[i].to;
if(v==fa[x]||v==son[x])continue;
dfs2(v,v);
}
}
static int LCA(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]>dep[top[y]]){
int t=x;x=y;y=t;
}
y=fa[top[y]];
}
if(dep[x]>dep[y]){
int t=x;x=y;y=t;
}
return x;
}
static M getHash(int u,int v,int x){
M ux=mul(sub(down[u],down[fa[x]]),inv[dep[x]]);
M xv=sub(up[v],mul(up[x],fac[dep[v]-dep[x]]));
return add(mul(ux,fac[dep[v]-dep[x]]),xv);//从右上左下
}
static void getPre(){
fac=new M[n+1];
inv=new M[n+1];
fa=new int[n+1];
son=new int[n+1];
siz=new int[n+1];
dep=new int[n+1];
top=new int[n+1];
head=new int[n+1];
e=new Edge[2*n+10];
cnt=0;
down=new M[n+1];//rha
up=new M[n+1];//ha
a=new int[n+1];
}
static void solve() throws Exception{
AReader input=new AReader();
// String fileName="";
// Scanner input=new Scanner(new FileReader(fileName));
// BufferedReader input = new BufferedReader(new FileReader(fileName));
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
String al="abcdefghijklmnopqrstuvwxyz";
char[] ac=al.toCharArray();
n=input.nextInt();
getPre();
getFac();
String string=" "+input.next();
char[] s=string.toCharArray();
for(int i=1;i<=n;++i){
a[i]=s[i]-'a'+1;
}
for(int i=1;i<=n;++i){
int x=input.nextInt();
addEdge(x,i);
addEdge(i,x);
}
dep[0]=-1;
dfs1(1,0);
dfs2(1,1);
m=input.nextInt();
while(m>0){
m--;
int x=input.nextInt();
int y=input.nextInt();
int p=LCA(x,y);
M rtol=getHash(x,y,p);
M ltor=getHash(y,x,p);
if(rtol.x==ltor.x&&rtol.y==ltor.y)out.println("YES");
else out.println("NO");
}
out.flush();
out.close();
}
public static void main(String[] args) throws Exception{
solve();
}
// public static final void main(String[] args) throws Exception {
// new Thread(null, new Tx2(), "线程名字", 1 << 27).start();
// }
// @Override
// public void run() {
// try {
// //原本main函数的内容
// solve();
//
// } catch (Exception e) {
// }
// }
static
class AReader{
BufferedReader bf;
StringTokenizer st;
public AReader(){
bf=new BufferedReader(new InputStreamReader(System.in));
st=new StringTokenizer("");
}
public String nextLine() throws IOException{
return bf.readLine();
}
public String next() throws IOException{
while(!st.hasMoreTokens()){
st=new StringTokenizer(bf.readLine());
}
return st.nextToken();
}
public char nextChar() throws IOException{
//确定下一个token只有一个字符的时候再用
return next().charAt(0);
}
public int nextInt() throws IOException{
return Integer.parseInt(next());
}
public long nextLong() throws IOException{
return Long.parseLong(next());
}
public double nextDouble() throws IOException{
return Double.parseDouble(next());
}
public float nextFloat() throws IOException{
return Float.parseFloat(next());
}
public byte nextByte() throws IOException{
return Byte.parseByte(next());
}
public short nextShort() throws IOException{
return Short.parseShort(next());
}
public BigInteger nextBigInteger() throws IOException{
return new BigInteger(next());
}
}
}