Skip to content

树上带修莫队 ​

cpp
namespace MoOnTreeDynamic{
    // 莫队带修
    // 用法:assign(n),加边,init(),添加询问,修改add函数,work()
    struct Node{
        int id,l,r,t,p;
    };
    // be块编号,[L,R]块边界,seq括号序,in入序,out出序,dep深度
    // par父节点数组,adj邻接表
    // top括号序长度,block块大小,tot块数量
    vector<int> be,L,R,seq,in,out,dep;
    vector<vector<int>> par,adj;
    int top,block,tot;

    vector<Node> que;// 询问
    vector<array<int,2>> c;// 带修辅助数组
    vector<int> st;// 状态数组
    bool cmp(Node x,Node y){
        return (be[x.l]^be[y.l])?be[x.l]<be[y.l]:((be[x.r]^be[y.r]?be[x.r]<be[y.r]:x.t<y.t));
    }
    void dfs(int u,int fa){
        seq[++top]=u;
        in[u]=top;
        par[u][0]=fa;
        dep[u]=dep[fa]+1;
        for(int i=1;i<=__lg(dep[u]);i++)par[u][i]=par[par[u][i-1]][i-1];
        for(auto v:adj[u]){
            if(v==fa)continue;
            dfs(v,u);
        }
        seq[++top]=u;
        out[u]=top;
    }
    int lca(int u,int v){
        if(dep[u]<dep[v])swap(u,v);
        while(dep[u]>dep[v])u=par[u][__lg(dep[u]-dep[v])];
        if(u==v)return u;
        for(int i=__lg(dep[u]);i>=0;i--){
            if(par[u][i]!=par[v][i])u=par[u][i],v=par[v][i];
        }
        return par[u][0];
    }
    void assign(int n){
        seq.assign(2*n+1,0);
        in.assign(n+1,0);
        out.assign(n+1,0);
        dep.assign(n+1,0);
        par.assign(n+1,vector<int>(__lg(n)+1,0));
        adj.assign(n+1,{});
        st.assign(n+1,0);
        que.clear();
        c={{0,0}};
        top=0;
    }
    void init(){
        dfs(1,0);
        block=pow(top,2.0/3),tot=(top+block-1)/block;
        be.assign(top+1,0);
        L.assign(tot+1,0);   
        R.assign(tot+1,0);
        for(int i=1;i<=tot;i++){
            L[i]=block*(i-1)+1,R[i]=min(block*i,top);
            for(int j=L[i];j<=R[i];j++)be[j]=i;
        }
    }
    void add_update(int x,int y){
        c.push_back({x,y});
    }
    void add_query(int u,int v){
        if(in[u]>in[v])swap(u,v);
        int p=lca(u,v);
        int id=que.size(),t=c.size()-1;
        if(p==u)que.push_back({id,in[u],in[v],t,0});
        else que.push_back({id,out[u],in[v],t,p});
    }
    void addEdge(int u,int v){
        adj[u].push_back(v);
    }
}
using namespace MoOnTreeDynamic;
void solve(){
    int n,m,q;
    cin>>n>>m>>q;
    vector<int> V(m+1),W(n+1),cnt(m+1),C(n+1);
    for(int i=1;i<=m;i++)cin>>V[i];
    for(int i=1;i<=n;i++)cin>>W[i],W[i]+=W[i-1];
    assign(n);
    for(int i=1;i<n;i++){
        int u,v;
        cin>>u>>v;
        addEdge(u,v);
        addEdge(v,u);
    }
    init();
    for(int i=1;i<=n;i++)cin>>C[i];
    for(int i=0;i<q;i++){
        int op,x,y;
        cin>>op>>x>>y;
        if(op==0)add_update(x,y);
        else add_query(x,y);
    }
    auto work=[&](){
        sort(que.begin(),que.end(),cmp);
        int res=0;
        auto add=[&](int x){
            st[x]^=1;
            res-=W[cnt[C[x]]]*V[C[x]];
            if(st[x])cnt[C[x]]++;
            else cnt[C[x]]--;
            res+=W[cnt[C[x]]]*V[C[x]];
        };
        auto change=[&](int t){
            int pos=c[t][0];
            if(st[pos]){
                add(pos);
                swap(C[pos],c[t][1]);
                add(pos);
            }
            else swap(C[pos],c[t][1]);
        };
        int l=1,r=0,t=0;
        vector<int> ans(que.size());
        for(int i=0;i<que.size();i++){
            auto [id,ql,qr,qt,p]=que[i];
            while(r<qr)add(seq[++r]);
            while(r>qr)add(seq[r--]);
            while(l<ql)add(seq[l++]);
            while(l>ql)add(seq[--l]);
            while(t<qt)change(++t);
            while(t>qt)change(t--);
            if(p)add(p);
            ans[id]=res;
            if(p)add(p);
        }
        return ans;
    };
    for(auto x:work())cout<<x<<"\n";
}