P3384 【模板】轻重链剖分

树链剖分模板

在这里插入图片描述


```cpp
/*
 * @Descripttion: P3384 【模板】轻重链剖分
 * @Author: Fantasy_421
 * @Date: 2021-03-16 19:45:27
 * @LastEditTime: 2021-03-16 21:17:14
 */

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <set>
#include <cmath>

#define int long long
#define ull unsigned long long
#define in1(a) scanf("%d", &a)
#define in2(a, b) scanf("%d%d", &a, &b)
#define in3(a, b, c) scanf("%d%d%d", &a, &b, &c)
#define in4(a, b, c, d) scanf("%d%d%d%d", &a, &b, &c, &d)
#define in1L(a) scanf("%lld", &a)
#define in2L(a, b) scanf("%lld%lld", &a, &b)
#define in3L(a, b, c) scanf("%lld%lld%lld", &a, &b, &c)
#define in4L(a, b, c, d) scanf("%lld%lld%lld%lld", &a, &b, &c, &d)
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define rep(i, a, b) for (int i = 1; i <= a; i += b)
#define YES cout << "YES\n"
#define NO cout << "NO\n"
#define endl '\n'
using namespace std;

const int N=1e5+50;
int MOD;
int n,m,r;

int w[N],h[N],idx=1,nw[N],pos[N],size[N],son[N],dep[N],fa[N],top[N];
int id=0;
struct node
{
    int ver,next;
}g[N<<1];

struct tr
{
    int sum,add;
}tree[N<<2];
void add(int u,int v)
{
    g[idx].ver=v;g[idx].next=h[u];h[u]=idx++;
}

void dfs(int u,int father,int depth)
{
    dep[u]=depth;
    size[u]=1;
    fa[u]=father;
    for(int i=h[u];i;i=g[i].next)
    {
        int ver=g[i].ver;
        if(ver!=father)
        {
            dfs(ver,u,depth+1);
            size[u]+=size[ver];
            if(size[son[u]]<size[ver])
                son[u]=ver;
        }
    }
}

void dfs(int u,int t)
{
    pos[u]=++id;nw[id]=w[u];top[u]=t;
    if(!son[u])
        return;
    dfs(son[u],t);
    for(int i=h[u];i;i=g[i].next)
    {
        int ver=g[i].ver;
        if(ver==fa[u]||ver==son[u])
            continue;
        dfs(ver,ver);
    }
}

void pushup(int u)
{
    tree[u].sum=tree[u<<1].sum+tree[u<<1|1].sum;
    tree[u].sum%=MOD;
}

void pushdowm(int u,int l,int r)
{
    tr &lc=tree[u<<1],&rc=tree[u<<1|1];
    int mid=(l+r)>>1;
    if(tree[u].add)
    {
        lc.add+=tree[u].add;
        rc.add+=tree[u].add;
        lc.add%=MOD;
        rc.add%=MOD;
        lc.sum+=(mid-l+1)*tree[u].add;
        rc.sum+=(r-mid)*tree[u].add;
        lc.sum%=MOD;
        rc.sum%=MOD;
        tree[u].add=0;
    }
}

void build(int p,int l,int r)
{
    if(l==r)
    {
        tree[p].sum=nw[r];
        return;
    }
    int mid=(l+r)>>1;
    build(p<<1,l,mid);
    build(p<<1|1,mid+1,r);
    pushup(p);
}

void update(int p,int s,int t,int L,int R,int k)
{
    if(s<=L&&R<=t)
    {
        tree[p].add+=k;
        tree[p].add%=MOD;
        tree[p].sum+=(R-L+1)*k;
        tree[p].sum%=MOD;
        return;
    }
    pushdowm(p,L,R);
    int mid=(L+R)>>1;
    if(s<=mid)
        update(p<<1,s,t,L,mid,k);
    if(mid<t)
        update(p<<1|1,s,t,mid+1,R,k);
    pushup(p);
}

int query(int p,int s,int t,int L,int R)
{
    if(s<=L&&R<=t)
    {
        return tree[p].sum;
    }
    pushdowm(p,L,R);
    int res=0;
    int mid=(L+R)>>1;
    if(s<=mid)
    {
        res+=query(p<<1,s,t,L,mid);
        res%=MOD;
    }
    if(mid<t)
    {
        res+=query(p<<1|1,s,t,mid+1,R);
        res%=MOD;
    }
    return res;
}

void update_path(int u,int v,int k)
{
    while(top[u]!=top[v])
    {
        if(dep[top[u]]<dep[top[v]])
            swap(u,v);
        update(1,pos[top[u]],pos[u],1,n,k);
        u=fa[top[u]];
    }
    if(dep[u]<dep[v])
        swap(u,v);
    update(1,pos[v],pos[u],1,n,k);
}

int query_path(int u,int v)
{
    int res=0;
    while(top[u]!=top[v])
    {
        if(dep[top[u]]<dep[top[v]])
            swap(u,v);
        res+=query(1,pos[top[u]],pos[u],1,n);
        res%=MOD;
        u=fa[top[u]];
    }
    if(dep[u]<dep[v])
        swap(u,v);
    res+=query(1,pos[v],pos[u],1,n);
    res%=MOD;
    return res;
}


signed main()
{
    IOS;
    cin>>n>>m>>r>>MOD;
    for(int i=1;i<=n;i++)
    {
        cin>>w[i];
    }
    for(int i=1;i<n;i++)
    {
        int u,v;
        cin>>u>>v;
        add(u,v),add(v,u);
    }
    dfs(r,-1,1);
    dfs(r,r);
    build(1,1,n);
    while(m--)
    {
        int t,x,y,z;
        cin>>t;
        if(t==1)
        {
            cin>>x>>y>>z;
            update_path(x,y,z);
        }
        else if(t==2)
        {
            cin>>x>>y;
            cout<<query_path(x,y)<<endl;
        }
        else if(t==3)
        {
            cin>>x>>z;
            update(1,pos[x],pos[x]+size[x]-1,1,n,z);
        }
        else
        {
            cin>>x;
            cout<<query(1,pos[x],pos[x]+size[x]-1,1,n)<<endl;
        }
    }
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值