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;
}
posted @ 2020-09-15 22:52  gmh77  阅读(183)  评论(0编辑  收藏  举报