• 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();
    }
    
  • 相关阅读:
    python实践分享:关于排序算法,怎么选择sort()或者sorted()?
    python面试题汇总第06期-正则表达式(内附7题及答案)
    2020年最全python面试题汇总第05期(内附字符串8题及答案)
    2020年最全python面试题汇总第04期(内附13题及答案)
    2020年最全python面试题汇总第03期(内附10题及答案)
    2020年最全python面试题汇总第02期(内附18题及答案)
    2020年最全python面试题汇总第02期(内附16题及答案)
    python爬虫从小白到高手 Day2 动态页面的爬取
    python爬虫从小白到高手 Day1 爬取百度音乐歌单
    python爬虫从小白到高手 Day0 综述
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12484269.html
Copyright © 2020-2023  润新知