Codeforces 504E. Misha and LCP on Tree 题解


题目链接:E. Misha and LCP on Tree

题目大意:洛谷


题解:这是我目前写过最难写的集训队作业。Codeforces 中不可多得的卡常题。

因为是字符串匹配问题,考虑哈希,每一个点维护到祖先的哈希值,然后查询的时候按照是从叶子向根还是从根向叶子分两个拼起来,然后用长链剖分做到 \(O(1)\) 查询 k 级祖先,二分答案即可,时间复杂度 \(O((n+m)\log n)\)。然后等你写完以为时限绰绰有余时,你会发现在 TLE 6 和 TLE 9 之间反复横跳。

所以你需要一些优化,比如说将 \(O(n\log n)-O(\log n)\) 的倍增求 LCA 改成 \(O(n\log n)-O(1)\) 的 RMQ 求 LCA,然后加读入输出优化,然后预处理 \(\log_2 x\) 的值等等。(这题的卡常难度对我而言和 Ynoi 有的一拼。

代码:(fread 的快读板子不是我的,是同校的一位神仙的。最慢点 7971 ms)

#include 
#include 
#include 
using namespace std;
namespace io {
#define File(s) freopen(s".in", "r", stdin), freopen(s".out", "w", stdout)
  const int SIZE = (1 << 21) + 1;
  char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1;
  inline char getc () {return (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++);}
  inline void flush () {fwrite (obuf, 1, oS - obuf, stdout); oS = obuf;}
  inline void putc (char x) {*oS ++ = x; if (oS == oT) flush ();}
  template
  inline void read(T &x) {
    char ch; int f = 1;
    x = 0;
    while(isspace(ch = getc()));
    if(ch == '-') ch = getc(), f = -1;
    do x = x * 10 + ch - '0'; while(isdigit(ch = getc()));
    x *= f;
  }
  template
  inline void read(T &x, Args&... args) {read(x); read(args...);}
  template
  inline void write(T x) {
    static char stk[128];
    int top = 0;
    if(x == 0) {putc('0'); return;}
    if(x < 0) putc('-'), x = -x;
    while(x) stk[top++] = x % 10, x /= 10;
    while(top) putc(stk[--top] + '0');
  }
  template
  inline void write(T x, Args... args) {write(x); putc(' '); write(args...);}
  inline void space() {putc(' ');}
  inline void endl() {putc('\n');}
  struct _flush {~_flush() {flush();}} __flush;
};
using io::read; using io::write; using io::flush; using io::space; using io::endl; using io::getc; using io::putc;

int quick_power(int a,int b,int Mod){
    int ans=1;
    while(b){
        if(b&1){
            ans=1ll*ans*a%Mod;
        }
        b>>=1;
        a=1ll*a*a%Mod;
    }
    return ans;
}
void add(int &x,int y,int Mod){
    x+=y;
    if(x>=Mod){
        x-=Mod;
    }
}
void del(int &x,int y,int Mod){
    x-=y;
    if(x<0){
        x+=Mod;
    }
}
typedef long long ll;
const int Maxn=300000;
const int Base[2]={107,59},Mod[2]={1004535809,1000000007};
int pow_b[2][Maxn+5],inv_b[2][Maxn+5];
int f[20][Maxn<<1|5];
int log_2[Maxn<<1|5];
int dfn[Maxn+5],rnk[Maxn<<1|5],dfn_tot;
void init(){
    for(register int i=0;i<2;++i){
        pow_b[i][0]=1;
        inv_b[i][0]=1;
        for(int j=1;j<=Maxn;++j){
            pow_b[i][j]=1ll*pow_b[i][j-1]*Base[i]%Mod[i];
            inv_b[i][j]=quick_power(pow_b[i][j],Mod[i]-2,Mod[i]);
        }
    }
    for(register int i=1;(1<>1]+1;
    }
}
char s[Maxn+5];
int head[Maxn+5],arrive[Maxn<<1|5],nxt[Maxn<<1|5],tot;
inline void add_edge(int from,int to){
    arrive[++tot]=to;
    nxt[tot]=head[from];
    head[from]=tot;
}
int n,m;
int dep[Maxn+5];
int fa[20][Maxn+5],mx_dep[Maxn+5];
int root;
int son[Maxn+5],top[Maxn+5];
void init_dfs_1(int u){
    for(register int i=1;fa[i-1][fa[i-1][u]];++i){
        fa[i][u]=fa[i-1][fa[i-1][u]];
    }
    dep[u]=dep[fa[0][u]]+1;
    mx_dep[u]=1;
    for(register int i=head[u];i;i=nxt[i]){
        int v=arrive[i];
        if(v==fa[0][u]){
            continue;
        }
        fa[0][v]=u;
        init_dfs_1(v);
        if(mx_dep[v]+1>mx_dep[u]){
            mx_dep[u]=mx_dep[v]+1;
            son[u]=v;
        }
    }
}
vector lis_up[Maxn+5],lis_down[Maxn+5];
void init_dfs_2(int u,int tp){
    lis_down[tp].push_back(u);
    if(u==tp){
        int len=0,tmp=u;
        while(tmp&&lenv){
        swap(u,v);
    }
    int k=log_2[v-u+1];
    return rnk[min(f[k][u],f[k][v-(1<dep[v]){
        ans=num_up[t][u];
        ans=(1ll*ans-num_up[t][fa[0][v]]+Mod[t])%Mod[t];
        ans=1ll*ans*inv_b[t][dep[v]-1]%Mod[t];
    }
    else{
        ans=num_down[t][v];
        ans=(ans-1ll*num_down[t][fa[0][u]]*pow_b[t][dep[v]-dep[u]+1]%Mod[t]+Mod[t])%Mod[t];
    }
    return ans;
}
inline int find_hash(int t,int u,int v,int lca,int k){
    if(dep[u]-dep[lca]>=k){
        return find_hash(t,u,find_kth(u,k));
    }
    int ans;
    if(u==lca){
        ans=0;
    }
    else{
        ans=find_hash(t,u,find_kth(u,dep[u]-dep[lca]-1));
    }
    k=(dep[u]+dep[v]-(dep[lca]<<1))-k;
    int tmp=find_hash(t,lca,find_kth(v,k));
    ans=(1ll*ans*pow_b[t][dep[v]-dep[lca]-k+1]+tmp)%Mod[t];
    return ans;
}
inline int query(int u_1,int v_1,int u_2,int v_2){
    if(s[u_1]!=s[u_2]){
        return 0;
    }
    int lca_1=find_lca(u_1,v_1),lca_2=find_lca(u_2,v_2);
    int len=min(dep[u_1]+dep[v_1]-(dep[lca_1]<<1),dep[u_2]+dep[v_2]-(dep[lca_2]<<1));
    int left=0,right=len;
    while(left>1;
        if(find_hash(0,u_1,v_1,lca_1,mid)==find_hash(0,u_2,v_2,lca_2,mid)&&find_hash(1,u_1,v_1,lca_1,mid)==find_hash(1,u_2,v_2,lca_2,mid)){
            left=mid;
        }
        else{
            right=mid-1;
        }
    }
    return left+1;
}
void init_dfs_4(int u){
    dfn[u]=++dfn_tot;
    f[0][dfn_tot]=dfn[u];
    rnk[dfn_tot]=u;
    for(register int i=head[u];i;i=nxt[i]){
        int v=arrive[i];
        if(v==fa[0][u]){
            continue;
        }
        init_dfs_4(v);
        f[0][++dfn_tot]=dfn[u];
    }
}
int main(){
//  freopen("input.txt","r",stdin);
//  freopen("output.txt","w",stdout);
    read(n);
    {
        char c=getc();
        while(c<'a'||c>'z'){
            c=getc();
        }
        int len=0;
        while(c>='a'&&c<='z'){
            s[++len]=c;
            c=getc();
        }
    }
    for(register int i=1;i