[P3384] 【模板】轻重链剖分 - 树链剖分

Description

已知一棵包含 \(N\) 个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作:

操作 \(1\): 格式: \(1\ x\ y\ z\) 表示将树从 \(x\) 到 \(y\) 结点最短路径上所有节点的值都加上 \(z\)。

操作 \(2\): 格式: \(2\ x\ y\) 表示求树从 \(x\) 到 \(y\) 结点最短路径上所有节点的值之和。

操作 \(3\): 格式: \(3\ x\ z\) 表示将以 \(x\) 为根节点的子树内所有节点值都加上 \(z\)。

操作 \(4\): 格式: \(4\ x\) 表示求以 \(x\) 为根节点的子树内所有节点值之和

Solution

复习一下模板

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N = 400005;

int val[N],tag[N];

void pushup(int p) {
    val[p]=val[p*2]+val[p*2+1];
}
void pushdown(int p,int l,int r) {
    if(tag[p]) {
        val[p*2]+=tag[p]*((l+r)/2-l+1);
        val[p*2+1]+=tag[p]*(r-(l+r)/2);
        tag[p*2]+=tag[p];
        tag[p*2+1]+=tag[p];
        tag[p]=0;
    }
}
void build(int p,int l,int r,int *src) {
    if(l==r) val[p]=src[l];
    else {
        build(p*2,l,(l+r)/2,src);
        build(p*2+1,(l+r)/2+1,r,src);
        pushup(p);
    }
}
void modify(int p,int l,int r,int ql,int qr,int key) {
    if(l>qr || r<ql) return;
    if(l>=ql && r<=qr) {
        val[p]+=(r-l+1)*key;
        tag[p]+=key;
    }
    else {
        pushdown(p,l,r);
        modify(p*2,l,(l+r)/2,ql,qr,key);
        modify(p*2+1,(l+r)/2+1,r,ql,qr,key);
        pushup(p);
    }
}
int query(int p,int l,int r,int ql,int qr) {
    if(l>qr || r<ql) return 0;
    if(l>=ql && r<=qr) {
        return val[p];
    }
    else {
        pushdown(p,l,r);
        return query(p*2,l,(l+r)/2,ql,qr)+query(p*2+1,(l+r)/2+1,r,ql,qr);
    }
}

vector <int> g[N];

int top[N],wson[N],siz[N],dep[N],vis[N],tid[N],did[N],fin[N],fa[N],cnt=0;

void link(int p,int q) {
    g[p].push_back(q);
    g[q].push_back(p);
}

void dfs1(int p) {
    vis[p]=siz[p]=1;
    for(int q:g[p]) if(vis[q]==0) {
        dep[q]=dep[p]+1;
        fa[q]=p;
        dfs1(q);
        siz[p]+=siz[q];
        if(siz[q]>siz[wson[p]]) wson[p]=q;
    }
}

void dfs2(int p) {
    did[p]=++cnt;
    tid[cnt]=p;
    vis[p]=1;
    if(wson[p]) top[wson[p]]=top[p],dfs2(wson[p]);
    for(int q:g[p]) if(vis[q]==0) {
        top[q]=q;
        dfs2(q);
    }
    fin[p]=cnt;
}

int n,m,r,mod,v[N],w[N];

void presolve() {
    dep[r]=1;
    dfs1(r);
    memset(vis,0,sizeof vis);
    top[r]=r;
    dfs2(r);
}



void link_modify(int p,int q,int v) {
    while(top[p]-top[q]) {
        if(dep[top[p]]>dep[top[q]]) swap(p,q);
        modify(1,1,n,did[top[q]],did[q],v);
        q=fa[top[q]];
    }
    if(dep[p]>dep[q]) swap(p,q);
    modify(1,1,n,did[p],did[q],v);
}

int link_query(int p,int q) {
    int ans=0;
    while(top[p]-top[q]) {
        if(dep[top[p]]>dep[top[q]]) swap(p,q);
        ans+=query(1,1,n,did[top[q]],did[q]);
        q=fa[top[q]];
    }
    if(dep[p]>dep[q]) swap(p,q);
    ans+=query(1,1,n,did[p],did[q]);
    return ans;
}

signed main() {
    ios::sync_with_stdio(false);
    cin>>n>>m>>r>>mod;
    for(int i=1;i<=n;i++) cin>>v[i];
    for(int i=1;i<n;i++) {
        int t1,t2;
        cin>>t1>>t2;
        link(t1,t2);
    }
    presolve();
    for(int i=1;i<=n;i++) w[did[i]]=v[i];
    build(1,1,n,w);
    for(int i=1;i<=m;i++) {
        int t1,t2,t3,t4;
        cin>>t1;
        if(t1==1) {
            cin>>t2>>t3>>t4;
            link_modify(t2,t3,t4);
        }
        if(t1==2) {
            cin>>t2>>t3;
            cout<<link_query(t2,t3)%mod<<endl;
        }
        if(t1==3) {
            cin>>t2>>t3;
            modify(1,1,n,did[t2],fin[t2],t3);
        }
        if(t1==4) {
            cin>>t2;
            cout<<query(1,1,n,did[t2],fin[t2])%mod<<endl;
        }
    }
}
上一篇:resultMap自定义映射(多对一)


下一篇:eolinker传参解决方法(截取返回数据中的某一段数据)