模板——树链剖分

放个板子而已。。

#include<stdio.h>
#include<algorithm>
#define ls root<<1
#define rs root<<1|1
using namespace std;
typedef long long ll;

int n,m,r;ll res,p;

const int MAXN = 100005;
ll a[MAXN];
struct edge{
    int v,nxt;
}e[MAXN<<1];

struct TREE{
    int lazy,l,r,val;
}tree[MAXN*4];
int head[MAXN];int cnt=0;int dep[MAXN];int fa[MAXN];int son[MAXN];int size[MAXN];int top[MAXN];int newval[MAXN];int id[MAXN];
int tot=0;

inline void add(int u,int v){
    e[++cnt].v = v;e[cnt].nxt = head[u];head[u] = cnt;
}

inline void pushdown(int root,int len){
    tree[ls].lazy += tree[root].lazy;
    tree[rs].lazy += tree[root].lazy;
    tree[ls].val += tree[root].lazy * (len-(len>>1));
    tree[rs].val += tree[root].lazy * (len>>1);
    tree[ls].val %= p;
    tree[rs].val %= p;
    tree[root].lazy = 0;
}

inline void update(int root,int L,int R,int l,int r,ll k){
    if(l <= L && R <= r){
        tree[root].lazy += k;
        tree[root].val += (R-L+1)*k;
    }
    else{
        int mid = (L + R) >> 1;
        if(tree[root].lazy) pushdown(root,R-L+1);
        if(l <= mid) update(ls,L,mid,l,r,k);
        if(r >= mid+1) update(rs,mid+1,R,l,r,k);
        tree[root].val = tree[ls].val + tree[rs].val;
        tree[root].val %= p;
    }
}

inline void query(int root,int L,int R,int l,int r){
    if(l <= L && R <= r){
        res += tree[root].val;
        res %= p;
        return ;
    }
    else{
        int mid = (L + R) >> 1;
        if(tree[root].lazy) pushdown(root,R-L+1);
        if(l <= mid) query(ls,L,mid,l,r);
        if(r >= mid+1) query(rs,mid+1,R,l,r);
    }
}

//////////////////////////线段树分割线////////////////////////////////////

inline void dfs1(int root,int father,int depth){
    dep[root] = depth;
    fa[root] = father;
    size[root] = 1;
    for(int i=head[root];i;i=e[i].nxt){
        int v = e[i].v;
        if(v == father) continue;
        dfs1(v,root,depth+1);
        size[root] += size[v];
        if(!son[root] || size[v] > size[son[root]]){
            son[root] = v;
        }
    }
}

inline void dfs2(int u,int nowtop){
    id[u] = ++tot;
    top[u] = nowtop;
    newval[tot] = a[u];
    if(!son[u]) return ;
    dfs2(son[u] , nowtop);
    for(int i=head[u];i;i=e[i].nxt){
        int v = e[i].v;
        if(v == fa[u] || v == son[u]) continue;
        dfs2(v,v);
    }
}

inline void build(int root,int l,int r){
    if(l == r){
        tree[root].val = newval[l];
        tree[root].val %= p;
        return ;
    }
    int mid = (l + r) >> 1;
    build(ls,l,mid);
    build(rs,mid+1,r);
    tree[root].val = tree[ls].val + tree[rs].val;
    tree[root].val %= p;
}

inline void addrange(int l,int r,ll num){
    while(top[l] ^ top[r]){
        if(dep[top[l]] < dep[top[r]]) swap(l,r);
        update(1,1,n,id[top[l]],id[l],num);
        l = fa[top[l]];
    }
    if(dep[l] > dep[r]) swap(l,r);
    update(1,1,n,id[l],id[r],num);
}

inline int queryrange(int l,int r){
    int ans = 0;
    while(top[l] ^ top[r]){
        if(dep[top[l]] < dep[top[r]]) swap(l,r);
        res=0;
        query(1,1,n,id[top[l]],id[l]);
        ans += res;
        ans %= p;
        l = fa[top[l]];
    }
    if(dep[l] > dep[r]) swap(l,r);
    res=0;
    query(1,1,n,id[l],id[r]);
    ans += res;
    return ans%p;
}

int main(){
    scanf("%d%d%d%lld",&n,&m,&r,&p);
    for(int i=1;i<=n;++i) scanf("%lld",&a[i]);
    for(int i=1;i<n;++i){
        int u,v;scanf("%d%d",&u,&v);
        add(u,v);add(v,u);
    }
    dfs1(r,0,1);
    dfs2(r,r);
    build(1,1,n);
    for(;m;--m){
        int k;scanf("%d",&k);
        switch (k){
            case 1:{
                int x,y;ll z;
                scanf("%d%d%lld",&x,&y,&z);
                z %= p;
                addrange(x,y,z);
                break;
            }
            case 2:{
                int x,y;
                scanf("%d%d",&x,&y);
                printf("%d\n",queryrange(x,y));
                break;
            }
            case 3:{
                int x;ll z;
                scanf("%d%lld",&x,&z);
                update(1,1,n,id[x],id[x]+size[x]-1,z);
                break;
            }
            case 4:{
                int x;scanf("%d",&x);
                res = 0;
                query(1,1,n,id[x],id[x]+size[x]-1);
                printf("%lld\n",res%p);
                break;
            }
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/lajioj/p/9479056.html

时间: 2024-10-07 18:24:22

模板——树链剖分的相关文章

[luogu P3384] [模板]树链剖分

[luogu P3384] [模板]树链剖分 题目描述 如题,已知一棵包含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为根节点的子树内所有节点值之和 输入输出格式 输入格式: 第一行包含4个正整数

luoguP3384 [模板]树链剖分

luogu P3384 [模板]树链剖分 题目 #include<iostream> #include<cstdlib> #include<cstdio> #include<cmath> #include<cstring> #include<iomanip> #include<algorithm> #include<ctime> #include<queue> #define rg register

[模板]树链剖分

原题链接:https://www.luogu.org/problemnew/show/P3384 树链剖分+线段树,备用. 等待补充详细解释中. /* 1 x y z x到y最短路径上加上z 2 x y 求x到y的最短路径上的节点值之和 3 x z 以x为根节点的子树内的所有节点值都加上z 4 x 以x为根节点的所有节点值之和 */ #include<cstdio> void read(int &y) { y=0;char x=getchar();int f=1; while(x<

模板 树链剖分BFS版本

//点和线段树都从1开始 //边使用vector vector<int> G[maxn]; int dfs_clock,que[maxn*2],num[maxn],iii[maxn],b[maxn],a[maxn],top[maxn],deep[maxn],fa[maxn],idx[maxn]; //采用静态链表 //a[i] 是初始时树上每个点的权值 //b[i] 是经过bfs后每个点的权值 //idx[i] 是每个点在全局线段树中的下标 void build_List() { int ft

[模板] 树链剖分找LCA

#include <cstdio> #include <cstring> #define MAX 500005 int d[MAX],fa[MAX],size[MAX],top[MAX],son[MAX]; int N,M,S,tot=0; int head[MAX]; struct edge{ int v,next; }G[MAX<<1]; inline void add(int u,int v){ G[++tot].v=v;G[tot].next=head[u];h

树链剖分[模板](洛谷 P3384)

洛谷·[模板]树链剖分 写在前面 首先,在学树链剖分之前最好先把 LCA.树形DP.DFS序 这三个知识点学了 如果这三个知识点没掌握好的话,树链剖分难以理解也是当然的. 树链剖分 树链剖分 就是对一棵树分成几条链,把树形变为线性,减少处理难度 概念 dfs1() dfs2() 对剖过后的树建线段树 处理问题 概念 重儿子:对于每一个非叶子节点,它的儿子中 儿子数量最多的那一个儿子 为该节点的重儿子 轻儿子:对于每一个非叶子节点,它的儿子中 非重儿子 的剩下所有儿子即为轻儿子 叶子节点没有重儿子

Hdu5044Tree 树链剖分

输入输出挂,扩栈挂,模板树链剖分. #include<iostream> #include<cstdio> #include<cstring> #include<map> #include<vector> #include<stdlib.h> #include<algorithm> using namespace std; const int maxn = 111111; struct Node { int next; i

树链剖分 模板

关于树链剖分 模板: 1 const int MAXN = 20010; 2 struct Edge 3 { 4 int to,next; 5 } edge[MAXN*2]; 6 int head[MAXN],tot; 7 8 int top[MAXN];//top[v]表示v所在的重链的顶端节点 9 int fa[MAXN]; //父亲节点 10 int deep[MAXN];//深度 11 int num[MAXN];//num[v]表示以v为根的子树的节点数 12 int p[MAXN];

luogu3384 【模板】树链剖分

P3384 [模板]树链剖分 题目描述 如题,已知一棵包含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为根节点的子树内所有节点值之和 输入输出格式 输入格式: 第一行包含4个正整数N.M.R.P,