P15534 【MYCOI R1】那猫猫城的集市 题解

第一次 div.2 场切 3 道!

题目大意

给定一棵树,每个点上有一个对换 \(\sigma_i=(a_i b_i)\)。\(q\) 次询问,每次给定 \(u,v,x\)。设 \(u\to v\) 路径上的点分别是 \(u,k_1,k_2,\dots,k_m,v\),求 \(\sigma_v\sigma_{k_m}\dots\sigma_{k_1}\sigma_u(x)\),即对路径上对换复合的单点求值。

Solution

注意到对换的逆就是其自身。尝试用类似树上前缀和的方法去做。

拿下面这棵树中 \(u=5,v=7\) 的询问举例。

\[\begin{aligned} &\sigma_7\sigma_6\sigma_3\sigma_4\sigma_5\left(x\right) \\ =&\left(\sigma_7\sigma_6\right)\sigma_3\left(\sigma_4\sigma_5\right)\left(x\right) \\ =&\left(\sigma_7\sigma_6\color{red}\sigma_3\sigma_2\sigma_1\color{blue}\sigma_1\sigma_2\sigma_3\color{black}\right)\sigma_3\left(\color{red}\sigma_3\sigma_2\sigma_1\color{blue}\sigma_1\sigma_2\sigma_3\color{black}\sigma_4\sigma_5\right)\left(x\right)\\ =&\left(\sigma_7\sigma_6\color{red}\sigma_3\sigma_2\sigma_1\color{black}\right)\left(\color{blue}\sigma_1\sigma_2\sigma_3\color{black}\right)\sigma_3\left(\color{red}\sigma_3\sigma_2\sigma_1\color{black}\right)\left(\color{blue}\sigma_1\sigma_2\sigma_3\color{black}\sigma_4\sigma_5\right)\left(x\right) \end{aligned} \]

这样一来,特殊处理 LCA 后我们就拆出了四个前缀对换积,可能是左乘,也可能是右乘。可以维护一个 \(n\) 阶排列表示当前对换积,同时维护其逆,则左右乘对换均可以做到 \(O(1)\)。然后离线下来把询问挂在链的端点,四遍 dfs 即可。

时间复杂度 \(O(n\log n)\)。实现精细的话可以把倍增 LCA 换成 Tarjan,做到 \(O(n\alpha(n))\)。

Code

cpp 复制代码
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i(a);i<b;++i)
#define per(i,a,b) for(int i(a);i>b;--i)
#define rept(i,a,b) for(int i(a);i<=b;++i)
#define pert(i,a,b) for(int i(a);i>=b;--i)
#define eb emplace_back
#define pii pair<int,int>
#define il inline
#define gc (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
#define pc putchar_unlocked
using namespace std;
constexpr int N=1e6+5;
char *p1,*p2,buf[1<<20];
il void rd(int &x){
    char c;
    while((c=gc)<'0'||c>'9');
    for(x=c^48;(c=gc)>='0'&&c<='9';x=(x<<3)+(x<<1)+(c^48));
}
il void wr(int x){
    x<10?pc(x|48):(wr(x/10),pc(x%10|48));
}
struct query{
    int u,anc,vp,v,x;
}q[N];
vector<int> g[N],vec[N];
int n,m;
int a[N],b[N];
int p[N],inv[N];
int dep[N],fa[20][N],lg[N];
void dfs(int u){
    rept(i,1,lg[dep[u]]) fa[i][u]=fa[i-1][fa[i-1][u]];
    for(int v:g[u]){
        if(v==fa[0][u]) continue;
        dep[v]=dep[u]+1,fa[0][v]=u;
        dfs(v);
    }
}
void reset(){
    rept(i,1,n){
        p[i]=inv[i]=i;
        vec[i].clear();
    }
}
il int lca(int u,int v){
    if(dep[u]<dep[v]) u^=v^=u^=v;
    int d=dep[u]-dep[v];
    rept(i,0,lg[d]) if(d>>i&1) u=fa[i][u];
    if(u==v) return u;
    pert(i,lg[dep[u]],0) if(fa[i][u]^fa[i][v]) u=fa[i][u],v=fa[i][v];
    return fa[0][u];
}
il void lmul(int a,int b){
    int pa=inv[a],pb=inv[b];
    swap(p[pa],p[pb]),swap(inv[a],inv[b]);
}
il void rmul(int a,int b){
    int pa=p[a],pb=p[b];
    swap(p[a],p[b]),swap(inv[pa],inv[pb]);
}
void solve_r(int u){
    rmul(a[u],b[u]);
    for(int id:vec[u]) q[id].x=p[q[id].x];
    for(int v:g[u]){
        if(v==fa[0][u]) continue;
        solve_r(v);
    }
    rmul(a[u],b[u]);
}
void solve_l(int u){
    lmul(a[u],b[u]);
    for(int id:vec[u]) q[id].x=p[q[id].x];
    for(int v:g[u]){
        if(v==fa[0][u]) continue;
        solve_l(v);
    }
    lmul(a[u],b[u]);
}
signed main(){
    rd(n),rd(m);
    rept(i,1,n) rd(a[i]);
    rept(i,1,n) rd(b[i]);
    rep(i,1,n){
        int u,v;rd(u),rd(v);
        g[u].eb(v),g[v].eb(u);
    }
    rep(i,2,n) lg[i]=lg[i>>1]+1;
    dfs(1);
    rept(i,1,m){
        rd(q[i].u),rd(q[i].v),rd(q[i].x);
        q[i].anc=lca(q[i].u,q[i].v);
    }

    reset();
    rept(i,1,m) vec[q[i].u].eb(i);
    solve_r(1);

    reset();
    rept(i,1,m) vec[q[i].anc].eb(i);
    solve_l(1);

    rept(i,1,m){
        if(q[i].x==a[q[i].anc]) q[i].x=b[q[i].anc];
        else if(q[i].x==b[q[i].anc]) q[i].x=a[q[i].anc];
    }

    reset();
    rept(i,1,m) vec[q[i].anc].eb(i);
    solve_r(1);

    reset();
    rept(i,1,m) vec[q[i].v].eb(i);
    solve_l(1);

    rept(i,1,m) wr(q[i].x),pc('\n');
    return 0;
}