CF504E Misha and LCP on Tree

Link
一个显然的做法是树剖+二分+Hash。
先树剖并预处理dfs序、从某个点到根的字符串以及它的反串的Hash值。
对于一个询问,我们把它拆成(O(log n))段重链。
利用dfs序我们可以快速地求重链上某个点的(k)级祖先,所以直接一段段重链做,每次二分一下就行了。
注意到如果有某一次二分中两段都未能走完,那么此时就可以退出了。也就是说只有一段是需要二分的。
这样子的话时间复杂度为(O(n+mlog n))

#include<cstdio>
#include<cctype>
#include<vector>
#include<utility>
#include<algorithm>
#define fi first
#define se second
using pi=std::pair<int,int>;
using vec=std::vector<pi>;
const int N=300007,P=1019260817;
char str[N];int n,fa[N],size[N],dep[N],son[N],top[N],dfn[N],id[N],pw[N],ipw[N],h[N][2];
std::vector<int>e[N];
int sgn(int x){return x<0? -1:1;}
int sub(int a,int b){return a-=b,a+=a>>31&P;}
int mul(int a,int b){return 1ll*a*b%P;}
int read(){int x=0,c=getchar();while(!isdigit(c))c=getchar();while(isdigit(c))(x*=10)+=c&15,c=getchar();return x;}
void dfs1(int u,int f)
{
    size[u]=1,dep[u]=dep[fa[u]=f]+1,h[u][0]=(str[u]+233ll*h[f][0])%P,h[u][1]=(h[f][1]+1ll*str[u]*pw[dep[u]-1])%P;
    for(int v:e[u]) if(v^f) dfs1(v,u),size[u]+=size[v],son[u]=size[v]>size[son[u]]? v:son[u];
}
void dfs2(int u,int t)
{
    static int T;top[u]=t,id[dfn[u]=++T]=u;
    if(son[u]) dfs2(son[u],t);
    for(int v:e[u]) if(v^fa[u]&&v^son[u]) dfs2(v,v);
}
vec split(int u,int v)
{
    vec l,r;
    while(top[u]^top[v]) dep[top[u]]>dep[top[v]]? (l.push_back({u,top[u]}),u=fa[top[u]]):(r.push_back({top[v],v}),v=fa[top[v]]);
    l.push_back({u,v}),std::reverse(r.begin(),r.end()),l.insert(l.end(),r.begin(),r.end());
    return l;
}
int ask(int x,int fx,int d){return fx==1? mul(sub(h[x][1],h[fa[id[dfn[x]-d+1]]][1]),ipw[dep[x]-d]):sub(h[id[dfn[x]+d-1]][0],mul(h[fa[x]][0],pw[d]));}
int cal(int u,int fu,int v,int fv,int lim)
{
    if(ask(u,fu,lim)==ask(v,fv,lim)) return lim;
    int l=1,r=lim-1;for(int mid;l<=r;) mid=(l+r)/2,ask(u,fu,mid)==ask(v,fv,mid)? l=mid+1:r=mid-1;
    return r;
}
void solve()
{
    int a=read(),b=read(),c=read(),d=read(),ans=0;vec l=split(a,b),r=split(c,d);
    for(int pl=0,pr=0,l1,l2,f1,f2,d,x;pl<(int)l.size()&&pr<(int)r.size();)
    {
	l1=abs(dep[l[pl].fi]-dep[l[pl].se])+1,l2=abs(dep[r[pr].fi]-dep[r[pr].se])+1,f1=sgn(dep[l[pl].fi]-dep[l[pl].se]),f2=sgn(dep[r[pr].fi]-dep[r[pr].se]),d=std::min(l1,l2);
	ans+=x=cal(l[pl].fi,f1,r[pr].fi,f2,d);if(d^x) break;
	(l1==d? ++pl:l[pl].fi=id[dfn[l[pl].fi]-f1*d]),(l2==d? ++pr:r[pr].fi=id[dfn[r[pr].fi]-f2*d]);
    }
    printf("%d
",ans);
}
int main()
{
    n=read(),scanf("%s",str+1),pw[0]=ipw[0]=1;
    for(int i=1;i<=n;++i) pw[i]=mul(233,pw[i-1]),ipw[i]=mul(78741179,ipw[i-1]);
    for(int i=1,u,v;i<n;++i) u=read(),v=read(),e[u].push_back(v),e[v].push_back(u);
    dfs1(1,0),dfs2(1,1);
    for(int m=read();m;--m) solve();
}
原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12484269.html