CF504E. Misha and LCP on Tree(长链剖分求k级祖先)
题目大意
题解
二分+hash判断
长链剖分求k级祖先
性质:一个点的k级祖先所在链长度>=k
证明:如果该点和祖先在同一条链上则得证,否则存在更长的链
在每条链顶维护往上/下len个,找的时候先跳到2i级祖先(2i<k且i最大),然后O(1)找即可
因为2^i级祖先所在链长度>=2^i,且k-2^i<2^i,所以可以找到
code
卡nmb常
#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(a,b) (a<b?a:b)
#define mod 1000000007
#define Mod 1000000005
#define ll long long
//#define file
using namespace std;
int a[600001][2],ls[300001],fa[300001][19],d[300001],nx[300001],f[300001],Len[300001],top[300001];
int bg1[300001],ed1[300001],b1[300001],bg2[300001],ed2[300001],b2[300001],mx[300001],p2[19];
ll p[300002],P[300002],hs1[300001],hs2[300001],np;
int Q,n,i,j,k,l,len,X1,Y1,X2,Y2,L,R,Mid,Lca1,Lca2;
char st[300001],ch,St[21];
ll qpower(ll a,int b) {ll ans=1; while (b) {if (b&1) ans=ans*a%mod;a=a*a%mod;b>>=1;} return ans;}
void New(int x,int y) {++len;a[len][0]=y;a[len][1]=ls[x];ls[x]=len;}
void Read(int &x) {x=0; ch=getchar(); while (ch<'0' || ch>'9') ch=getchar(); while (ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();}
void Write(int x) {if (!x) {putchar('0');putchar('\n');return;}int i=0; while (x) St[++i]=x%10+'0',x/=10; while (i) putchar(St[i--]);putchar('\n');}
void swap(int &x,int &y) {int z=x;x=y;y=z;}
int lca(int x,int y)
{
int i;
if (d[x]<d[y]) swap(x,y);
fd(i,18,0) if (d[fa[x][i]]>=d[y]) x=fa[x][i];
fd(i,18,0) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
if (x!=y) x=fa[x][0];
return x;
}
void dfs(int Fa,int t)
{
int i;
fa[t][0]=Fa;
d[t]=d[Fa]+1;
fo(i,1,18) fa[t][i]=fa[fa[t][i-1]][i-1];
hs1[t]=(hs1[Fa]*27+(st[t]-'a'+1))%mod;
hs2[t]=(hs2[Fa]+p[d[t]]*(st[t]-'a'+1))%mod;
for (i=ls[t]; i; i=a[i][1])
if (a[i][0]!=Fa)
{
dfs(t,a[i][0]);
if (f[a[i][0]]+1>f[t])
f[t]=f[a[i][0]]+1,nx[t]=a[i][0];
}
}
ll get1(int x,int y) {return hs1[y]-hs1[fa[x][0]]*p[d[y]-d[x]+1];}
ll get2(int x,int y) {return (hs2[y]-hs2[x])*P[d[x]+1];}
void Dfs(int Fa,int t)
{
int i;
if (nx[t])
{
Len[nx[t]]=Len[t]+1,top[nx[t]]=top[t];
Dfs(t,nx[t]);
}
for (i=ls[t]; i; i=a[i][1])
if (a[i][0]!=Fa && a[i][0]!=nx[t])
top[a[i][0]]=a[i][0],Len[a[i][0]]=0,Dfs(t,a[i][0]);
if (nx[Fa]==t) Len[Fa]=Len[t];
}
void Init()
{
np=qpower(27,Mod);
p[0]=P[0]=1;
fo(i,1,n+1) p[i]=p[i-1]*27%mod,P[i]=P[i-1]*np%mod;
}
void init()
{
top[1]=1,Dfs(0,1);
l=0;
fo(i,1,n)
if (nx[fa[i][0]]!=i)
{
bg1[i]=l+1,k=i;
fo(j,0,Len[i])
{
++l;
b1[l]=k,k=fa[k][0];
if (!k) break;
}
ed1[i]=l;
}
l=0;
fo(i,1,n)
if (nx[fa[i][0]]!=i)
{
bg2[i]=l+1,k=i;
fo(j,0,Len[i])
++l,b2[l]=k,k=nx[k];
ed2[i]=l;
}
fo(i,1,n) mx[i]=floor(log2(i));
p2[0]=1;fo(i,1,18) p2[i]=p2[i-1]*2;
}
int jump(int t,int s)
{
int i,j,k,l;
if (!s) return t;
t=fa[t][mx[s]],s-=p2[mx[s]];
if (d[t]-d[top[t]]<s)
return b1[bg1[top[t]]+s-(d[t]-d[top[t]])];
else
return b2[bg2[top[t]]+(d[t]-d[top[t]])-s];
}
ll get(int x,int y,int lca,int s)
{
int i,j,k,l;
ll s1,s2;
if (lca==x)
{
k=jump(y,(d[y]-d[x]+1)-s);
return get2(fa[x][0],k);
}
else
if (lca==y)
{
k=jump(x,s-1);
return get1(k,x);
}
else
{
if (s<=d[x]-d[lca]+1)
{k=jump(x,s-1);return get1(k,x);}
else
{s1=get1(lca,x),k=jump(y,(d[x]+d[y]-2*d[lca]+1)-s),s2=get2(lca,k)%mod;return s1+s2*p[d[x]-d[lca]+1];}
}
}
int main()
{
#ifdef file
freopen("CF504E.in","r",stdin);
freopen("a.out","w",stdout);
#endif
Read(n);
scanf("%s",st+1);
fo(i,1,n-1) Read(j),Read(k),New(j,k),New(k,j);
Init();
dfs(0,1);
init();
Read(Q);
for (;Q;--Q)
{
Read(X1),Read(Y1),Read(X2),Read(Y2);
Lca1=lca(X1,Y1),Lca2=lca(X2,Y2);
L=1,R=min(d[X1]+d[Y1]-d[Lca1]*2,d[X2]+d[Y2]-d[Lca2]*2)+1;
while (L<R)
{
Mid=(L+R)/2;
if (!((get(X1,Y1,Lca1,Mid)-get(X2,Y2,Lca2,Mid))%mod))
L=Mid+1; else R=Mid;
}
L-=(get(X1,Y1,Lca1,L)-get(X2,Y2,Lca2,L))%mod!=0;
Write(L);
}
fclose(stdin);
fclose(stdout);
return 0;
}