CF/AT 乱做

CF504E Misha and LCP on Tree [*3000]

原题链接

Solution

垃圾题。
考虑 LCP 问题的经典解法,二分一个前缀,判定这个前缀能否成为 LCP。
判定前缀考虑 Hash,需要预处理出每个点从根到它,从它到根的哈希值。
然后我们发现,每次二分之后需要找终点,这个得 \(O(1)\) 做,使用长链剖分求 k 级祖先就可以了。
然后你就判判判,然后你就*要卡常,总之就很离谱。
时间复杂度 \(O(m\log n)\),其中 \(\log n\) 是倍增 LCA。
然后用 ST 表 LCA 可以做到 \(O(n\log n+m)\),不过我没写。

Code
/*
Author: cnyz
----------------
Looking! The blitz loop this planet to search way.
Only my RAILGUN can shoot it. 今すぐ
*/
#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
#include<bits/stdc++.h>
using namespace std;

typedef double db;
typedef long long ll;
typedef pair<int,int> pii;
typedef unsigned int uint;
#define pb push_back
#define mp make_pair
#define fi first
#define se second

template <typename T> void chkmax(T &x,T y) {
    if(x<y) x=y;
}
template <typename T> void chkmin(T &x,T y) {
    if(x>y) x=y;
}

const int MAXL=1<<22;
char i_str[MAXL],o_str[MAXL],*i_s,*i_t;
int o_t;
inline char gc() {
    if(i_s==i_t) {
        i_s=i_str;
        i_t=i_s+fread(i_str,1,MAXL,stdin);
        return i_s==i_t?EOF:*i_s++;
    } else return *i_s++;
}
inline void gs(char *s) {
    *s=gc();
    while(*s==' '||*s=='\n')*s=gc();
    while(*s!=' '&&*s!='\n')*++s=gc();
    *s='\0';
}
inline int read() {
    int x=0,f=0;
    char ch=gc();
    for(; ch<'0'||ch>'9'; ch=gc())
        if(ch=='-')f=1;
    for(; ch>='0'&&ch<='9'; ch=gc())
        x=(x<<1)+(x<<3)+(ch^48);
    return f?~x+1:x;
}
#define fl fwrite(o_str,1,o_t,stdout),o_t=0
inline void pc(char x) {
    o_str[o_t++]=x;
    if(o_t==MAXL)fl;
}
inline void write(ll x) {
    if(x<0)x=-x,pc('-');
    if(x>9)write(x/10);
    pc(x%10^48);
}

const int mod=998244353;
const int base=13331;
const int N=6e5;
int Up[N+10],Down[N+10];
int n,q,h[N+10],ju[N+10][20];
vector<int> G[N+10];
int md[N+10],dep[N+10],hson[N+10],top[N+10];
int po[N+10],inv[N+10];
int pos[N+10],dfn[N+10],jp[N+10],dc;
char ch[N+10];
int fpow(int x,int y) {
    int ret=1;
    for(;y;y>>=1) {
        if(y&1) ret=1ll*ret*x%mod;
        x=1ll*x*x%mod;
    }
    return ret;
}
void ad(int u) {
    Down[u]=(1ll*Down[ju[u][0]]*base+ch[u])%mod;
    Up[u]=(Up[ju[u][0]]+1ll*po[dep[ju[u][0]]]*ch[u])%mod;
    dep[u]=dep[ju[u][0]]+1;
    for(int i=1;i<=19;i++) ju[u][i]=ju[ju[u][i-1]][i-1];
    for(auto v:G[u]) {
        if(v==ju[u][0]) continue;
        ju[v][0]=u;ad(v);
        if(md[v]+1>md[u]) md[u]=md[hson[u]=v]+1;
    }
}
void dfs(int u) {
    if(hson[ju[u][0]]==u) top[u]=top[ju[u][0]];
    else top[u]=u;
    pos[dfn[u]=++dc]=u;
    if(hson[u]) dfs(hson[u]);
    for(auto v:G[u]) {
        if(v==ju[u][0]||v==hson[u]) continue;
        dfs(v);
        jp[dfn[v]]=u;
        for(int i=1;i<=md[v];i++)
            jp[dfn[v]+i]=ju[jp[dfn[v]+i-1]][0];
    }
}
int LCA(int u,int v) {
    if(u==v) return u;
    if(dep[u]<dep[v]) swap(u,v);
    for(int i=19;i>=0;i--)
        if(dep[ju[u][i]]>=dep[v])
            u=ju[u][i];
    if(u==v) return u;
    for(int i=19;i>=0;i--)
        if(ju[u][i]!=ju[v][i])
            u=ju[u][i],v=ju[v][i];
    return ju[u][0];
}
int calc(int u,int k) {
    return jp[dfn[u]+k-1];
}
int ask(int u,int k) {
    if(!k) return u;
    u=ju[u][h[k]];
    k-=1<<h[k];
    if(dep[u]-dep[top[u]]<k)
        return calc(top[u],-dep[u]+k+dep[top[u]]);
    else return pos[dfn[u]-k];
}
void init() {
    ad(1);
    // up[1].pb(1);
    // for(int i=1;i<=md[1];i++) up[1].pb(ju[up[1].back()][0]);
    dfs(1);
}
int get(int a,int b,int p) {
    if(p==-1) p=b;
    int H1=1ll*(Up[a]-Up[ju[p][0]]+mod)*inv[dep[p]-1]%mod;
    int H2=(Down[b]-1ll*Down[p]*po[dep[b]-dep[p]]%mod+mod)%mod;
    return (1ll*H1*po[dep[b]-dep[p]]+H2)%mod;
}
int query(int a,int b,int c,int d) {
    int lca1=LCA(a,b),lca2=LCA(c,d);
    int dis1=dep[a]+dep[b]-2*dep[lca1]+1,
        dis2=dep[c]+dep[d]-2*dep[lca2]+1;
    int l=1,r=min(dis1,dis2);
    while(l<=r) {
        int mid=(l+r)>>1;
        // printf("[%d,%d] is %d\n",l,r,mid);
        int h1=0,h2=0;
        if(dep[a]-dep[lca1]+1>=mid) h1=get(a,ask(a,mid-1),-1);
        else h1=get(a,ask(b,dis1-mid),lca1);
        if(dep[c]-dep[lca2]+1>=mid) h2=get(c,ask(c,mid-1),-1);
        else h2=get(c,ask(d,dis2-mid),lca2);
        // printf("%d %d\n",h1,h2);
        if(h1==h2) l=mid+1;
        else r=mid-1;
    }
    return l-1;
}
int main() {
    n=read();
    gs(ch+1);
    po[0]=inv[0]=1;
    po[1]=base,inv[1]=fpow(base,mod-2);
    for(int i=2,x,y;i<=n;i++) {
        x=read(),y=read();
        G[x].pb(y),G[y].pb(x);
        po[i]=1ll*po[i-1]*base%mod,
        h[i]=h[i/2]+1,
        inv[i]=1ll*inv[i-1]*inv[1]%mod;
    }
    init();
    q=read();
    while(q--) {
        int a,b,c,d;
        a=read(),b=read(),c=read(),d=read();
        write(query(a,b,c,d)),pc('\n');
    }
    return fl;
}
上一篇:使用SpringBoot+axios+hutool进行Excel的导出工作,并且在前端响应字符串的问题处理


下一篇:Hutool笔记总索引