树链剖分(模板)

问题:给你一棵树,完成下列操作:
1——给两点x,y之间的最短路径上的点权值加上z
2——查询两点x,y间最短距离经过的点的权值之和
3——给点x,让以x为根的子树权值加上z
4——查询以x为根的子树的权值之和

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define IO ios::sync_with_stdio(false)
#define bug cout << "-----\n"
typedef long long ll;
const int N = 100010;
const int M = 500010;
int cnt , ans , Mod;
int a[N],f[N],d[N],siz[N],top[N],son[N],id[N],ne[N];
vector<int> vt[N];
struct Tree {
    int l,r,num,lazy;
}tree[N << 2];
void build(int x,int l,int r) {
    tree[x].l = l;tree[x].r = r;
    if(l == r) {
        tree[x].num = ne[l] % Mod;
        return ;
    }
    int mid = (l + r) >> 1;
    build(x << 1 , l , mid);
    build(x << 1 | 1 , mid + 1 , r);
    tree[x].num = (tree[x << 1].num + tree[x << 1 | 1].num) % Mod;
}
void pushdown(int x) {
    int t = tree[x].lazy;
    if(t) {
        tree[x << 1].lazy += t;
        tree[x << 1 | 1].lazy += t;
        tree[x << 1].num += (tree[x << 1].r - tree[x << 1].l + 1) * t;
        tree[x << 1 | 1].num += (tree[x << 1 | 1].r - tree[x << 1 | 1].l + 1) * t;
        tree[x].lazy = 0;
    }
}
void update(int x,int l,int r,int t) {
    if(tree[x].l >= l && tree[x].r <= r) {
        tree[x].num += (tree[x].r - tree[x].l + 1) * t;
        tree[x].lazy += t;
        return ;
    }
    pushdown(x);
    if(r <= tree[x << 1].r)update(x << 1 , l , r , t);
    else if(l >= tree[x << 1 | 1].l)update(x << 1 | 1 , l , r , t);
    else {
        update(x << 1 , l , tree[x << 1].r , t);
        update(x << 1 | 1 , tree[x << 1 | 1].l , r , t);
    }
    tree[x].num = (tree[x << 1].num + tree[x << 1 | 1].num) % Mod;
}
void find(int x,int l,int r) {
    if(tree[x].l >= l && tree[x].r <= r) {
        ans += tree[x].num;
        ans %= Mod;
        return ;
    }
    pushdown(x);
    if(r <= tree[x << 1].r)find(x << 1 , l , r);
    else if(l >= tree[x << 1 | 1].l)find(x << 1 | 1 , l , r);
    else {
        find(x << 1 , l , tree[x << 1].r);
        find(x << 1 | 1 , tree[x << 1 | 1].l , r);
    }
}
void dfs1(int x,int fa,int deap) {
    int i;
    f[x] = fa;
    d[x] = deap;
    siz[x] = 1;
    int bigson = -1;
    for(i = 0 ; i < vt[x].size() ; i ++) {
        int to = vt[x][i];
        if(to == fa)continue;
        dfs1(to , x , deap + 1);
        siz[x] += siz[to];
        if(siz[to] > bigson)bigson = siz[to],son[x] = to;
    }
}
void dfs2(int x,int tp) {
    int i;
    id[x] = ++ cnt;
    ne[cnt] = a[x];
    top[x] = tp;
    if(!son[x])return ;
    dfs2(son[x] , tp);
    for(i = 0 ; i < vt[x].size() ; i ++) {
        int t = vt[x][i];
        if(t == f[x] || t == son[x])continue;
        dfs2(t , t);
    }
}
int find_p2p(int x,int y) {
    int res = 0;
    while(top[x] != top[y]) {
        if(d[top[x]] < d[top[y]]) swap(x , y);
        ans = 0;
        find(1 , id[top[x]] , id[x]);
        res += ans;
        res %= Mod;
        x = f[top[x]];
    }
    if(d[x] > d[y]) swap(x , y);
    ans = 0;
    find(1 , id[x] , id[y]);
    res += ans;res %= Mod;
    return res;
}
int find_son(int x) {
    ans = 0;
    find(1 , id[x] , id[x] + siz[x] - 1);
    return ans;
}
void update_p2p(int x,int y,int t) {
    t %= Mod;
    while(top[x] != top[y]) {
        if(d[top[x]] < d[top[y]])swap(x , y);
        update(1 , id[top[x]] , id[x] , t);
        x = f[top[x]];
    }
    if(d[x] > d[y])swap(x , y);
    update(1 , id[x] , id[y] , t);
}
void update_son(int x,int t) {
    update(1 , id[x] , id[x] + siz[x] - 1 , t);
}

int main() {
    int n , m , r , i , j , x , y , z , c;
    cin >> n >> m >> r >> Mod;
    for(i = 1 ; i <= n ; i ++)
        cin >> a[i];
    for(i = 1 ; i < n ; i ++) {
        cin >> x >> y;
        vt[x].push_back(y);
        vt[y].push_back(x);
    }
    dfs1(r , 0 , 1);
    dfs2(r , r);
    build(1 , 1 , n);
    while(m --) {
        cin >> c;
        if(c == 1) {
            cin >> x >> y >> z;
            update_p2p(x , y , z);
        }
        else if(c == 2) {
            cin >> x >> y;
            cout << find_p2p(x , y) << endl;
        }
        else if(c == 3) {
            cin >> x >> z;
            update_son(x , z);
        }
        else {
            cin >> x;
            cout << find_son(x) << endl;
        }
    }
    system("pause");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值