树链剖分 https://www.luogu.com.cn/problem/P3384

#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <iostream>
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
int N,M,R,P;
int deep[maxn],F[maxn],size_[maxn],son[maxn];//深度,父亲节点,子树大小,重儿子
vector<int> G[maxn];
void dfs1(int x,int f)
{
    int son_zhong=0,son_num=0;
    size_[x]=1;
    for(int i=0;i<G[x].size();i++)
    {
        int v=G[x][i];
        if(v==f)
            continue;
        F[v]=x;
        deep[v]=deep[x]+1;
        dfs1(v, x);
        size_[x]+=size_[v];
        if(son_num<size_[v])
        {
            son_num=size_[v];
            son_zhong=v;
        }
    }
    son[x]=son_zhong;
}
int id[maxn],id_inv[maxn],wt[maxn],w[maxn],top[maxn];
int cnt;
void dfs2(int x,int topt)
{
    id[x]=++cnt;
    top[id[x]]=topt;
    wt[id[x]]=w[x];
    if(son[x]!=0)
        dfs2(son[x], topt);
    for(int i=0;i<G[x].size();i++)
    {
        int v=G[x][i];
        if(v==F[x]||v==son[x])
            continue;
        dfs2(v, v);
    }
}
//区间查询 区间更新线段树

ll tree[maxn<<2],lazy[maxn<<2];
void pushdown(int rt,int l,int r){
    
    lazy[lson]=(lazy[lson]+lazy[rt])%P;
    lazy[rson]=(lazy[rson]+lazy[rt])%P;
    int mid=(l+r)/2;
    tree[lson]=(tree[lson]+lazy[rt]*(mid-l+1))%P;
    tree[rson]=(tree[rson]+lazy[rt]*(r-mid))%P;
    lazy[rt]=0;
}
void pushup(int rt)
{
    tree[rt]=(tree[lson]+tree[rson])%P;
}
void build(int rt,int l,int r)
{
    if(l==r)
    {
        tree[rt]=wt[l];
        return;
    }
    int mid=(l+r)/2;
    build(lson,l,mid);
    build(rson,mid+1,r);
    pushup(rt);
}

void update(int x,int L,int R,int l,int r,int rt)
{
    pushdown(rt, l, r);
    if(L<=l&&r<=R)
    {
        tree[rt]=(tree[rt]+(r-l+1)*x);
        lazy[rt]=(x)%P;
        return;
    }
    int mid=(l+r)/2;
    if(mid>=L)
        update(x, L, R, l,mid,lson);
    if(mid<R)
        update(x, L, R, mid+1,r,rson);
    
    pushup(rt);
}
ll query(int L,int R,int l,int r,int rt)
{
    pushdown(rt,l,r);
    if(L<=l&&r<=R)
    {
        return tree[rt];
    }
    int mid=(r+l)/2;
    ll ans=0;
    if(mid>=L)
        ans=(ans+query(L, R, l,mid,lson))%P;
    if(mid<R)
        ans=(ans+query(L, R, mid+1,r,rson))%P;
    return ans;
}
int main()
{
    cin>>N>>M>>R>>P;
    for(int i=1;i<=N;i++)
        cin>>w[i];
    for(int i=0;i<N-1;i++)
    {
        int u,v;
        cin>>u>>v;
        G[u].push_back(v);
        G[v].push_back(u);
    }
    dfs1(R, R);
    
    dfs2(R, R);
    for(int i=1;i<=N;i++)
        id_inv[id[i]]=i;
    
    build(1, 1, N);
    
    for(int i=0;i<M;i++)
    {
        int flag;
        cin>>flag;
        if(flag==1)
        {
            int x,y,z;
            cin>>x>>y>>z;
            x=id[x];
            y=id[y];
            while(1)
            {
                if(deep[top[x]]<deep[top[y]])
                    swap(x, y);
                
                if(top[x]==top[y])
                {
                    if(x<y)
                        swap(x, y);
                    update(z, y, x, 1, N, 1);
                    break;
                }
                else
                {
                    
                    update(z, id[top[x]], x, 1, N, 1);
                    x=id[F[top[x]]];
                }
            }
        }
        else if(flag==2)
        {
            int x,y;
            cin>>x>>y;
            x=id[x];
            y=id[y];
            ll ans=0;
            while(1)
            {
                if(deep[top[x]]<deep[top[y]])
                    swap(x, y);
                
                if(top[x]==top[y])
                {
                    if(x<y)
                        swap(x, y);
                    ans=(ans+query( y, x, 1, N, 1))%P;
                    break;
                }
                else
                {
                    ans=(ans+query(id[top[x]], x, 1, N, 1))%P;
                    x=id[F[top[x]]];
                }
            }
            cout<<ans<<endl;
        }
        else if(flag==3)
        {
            int x,z;
            cin>>x>>z;
            update(z, id[x], id[x]+size_[x]-1, 1, N, 1);
        }
        else if(flag==4)
        {
            int x;
            cin>>x;
            cout<<query(id[x], id[x]+size_[x]-1, 1, N, 1)<<endl;
        }
    }
}
原文地址:https://www.cnblogs.com/King-of-Dark/p/12272926.html