[模板]树链剖分

#include<bits/stdc++.h>
#define lson(x) (x << 1)
#define rson(x) (x << 1 | 1)
using namespace std;

const int N = 100010,M = 200010;
int n,m,r,p;
long long a[N];
int d[N],son[N],fa[N],siz[N],top[N],rk[N],id[N],cnt;//树链剖分 
int head[N],edge[M],nxt[M],from[M],to[M],tot;//邻接表 
void add_edge(int x,int y){
    from[++tot] = x;
    to[tot] = y;
    nxt[tot] = head[x];
    head[x] = tot;
}

//线段树
struct Tree{
    int l,r;
    long long sum,tag;  
}t[N*4];
void push_up(int x) { t[x].sum = (t[lson(x)].sum + t[rson(x)].sum) % p; }
void push_down(int x){
    if(t[x].tag){
        t[lson(x)].tag = (t[lson(x)].tag + t[x].tag) % p; 
        t[lson(x)].sum = (t[lson(x)].sum + t[x].tag *(t[lson(x)].r - t[lson(x)].l + 1)) % p;
        t[rson(x)].tag = (t[rson(x)].tag + t[x].tag) % p; 
        t[rson(x)].sum = (t[rson(x)].sum + t[x].tag *(t[rson(x)].r - t[rson(x)].l + 1)) % p;
        t[x].tag = 0;
    }
}
void build(int x,int ll,int rr){
    t[x].l = ll; t[x].r = rr;
    if(ll == rr) { 
        t[x].sum = a[rk[ll]]; 
        if(t[x].sum > p) t[x].sum %= p; 
        return; 
    }
    int mid = (ll + rr) >> 1;
    build(lson(x),ll,mid);
    build(rson(x),mid + 1,rr);
    push_up(x);
}
void update(int x,int ll,int rr,int k){
    if(ll <= t[x].l && t[x].r <= rr){
        t[x].sum = (t[x].sum + k * (t[x].r - t[x].l + 1)) % p;
        t[x].tag = (t[x].tag + k) % p;
        return;
    }
    push_down(x);
    int mid = (t[x].l + t[x].r) >> 1;
    if(ll <= mid) update(lson(x),ll,rr,k);
    if(mid < rr)  update(rson(x),ll,rr,k);
    push_up(x);
}
long long query(int x,int ll,int rr){
    if(ll <= t[x].l && t[x].r <= rr) return t[x].sum;
    int mid = (t[x].l + t[x].r) >> 1;
    long long res = 0;
    push_down(x);
    if(ll <= mid) res = (res + query(lson(x),ll,rr)) % p;
    if(mid < rr)  res = (res + query(rson(x),ll,rr)) % p;
    push_up(x);
    return res;
}

//树链剖分 
void dfs1(int x){
    siz[x] = 1;
    for(int i = head[x]; i; i = nxt[i])
        if(!siz[to[i]]){
            d[to[i]] = d[x] + 1;
            fa[to[i]] = x;
            dfs1(to[i]);
            siz[x] +=  siz[to[i]];
            if(!son[x] || siz[to[i]] > siz[son[x]])
                son[x] = to[i];
        }
}
void dfs2(int x,int t){
    top[x] = t;
    id[x] = ++cnt;
    rk[cnt] = x;
    if(!son[x]) return;
    dfs2(son[x],t);
    for(int i = head[x]; i; i = nxt[i])
        if(to[i] != son[x] && to[i] != fa[x])
            dfs2(to[i],to[i]);
}
int main(){
//    freopen("testdata (6).in","r",stdin);
//    freopen("test.txt","w",stdout);
    cin >> n >> m >> r >> p;
    for(int i = 1; i <= n; i++)
        scanf("%lld",&a[i]);
    for(int i = 1; i < n; i++){
        int x,y;
        scanf("%d%d",&x,&y);
        add_edge(x,y);
        add_edge(y,x);
    }
    dfs1(r);
    dfs2(r,r);
    build(1,1,n);
    for(int i = 1; i <= m; i++){
        int op = 0,x = 0,y = 0,z = 0;
        scanf("%d%d",&op,&x);
        if(op == 1){
            scanf("%d%d",&y,&z);
            while(top[x] != top[y]){
                if(d[top[y]] > d[top[x]]) swap(x,y);
                update(1,id[top[x]],id[x],z);
                x = fa[top[x]];
            }
            if(d[x] > d[y]) swap(x,y);
                update(1,id[x],id[y],z);
        }
        if(op == 2){
            scanf("%d",&y);
            long long ans = 0;
            while(top[x] != top[y]){
                if(d[top[y]] > d[top[x]]) swap(x,y);
                ans = (ans + query(1,id[top[x]],id[x])) % p;
                x = fa[top[x]];
            }
            if(d[x] > d[y]) swap(x,y);
            ans = (ans + query(1,id[x],id[y]))% p;
            printf("%lld\n",ans);
        }
        if(op == 3){
            scanf("%d",&z);
            update(1,id[x],id[x] + siz[x] - 1,z);
        }
        if(op == 4){
            printf("%lld\n",query(1,id[x],id[x] + siz[x] - 1));
        } 
    }
    return 0;
}

转载于:https://www.cnblogs.com/FoxC/p/11256624.html

《C++编程实例100篇》是一本深入实践、极具价值的编程教程,它针对C++编程语言提供了丰富的实例,旨在帮助读者更好地理解和掌握C++的各项特性与编程技巧。这本书的经典之处在于它将理论与实践相结合,通过100个精心设计的编程实例,覆盖了C++的各个核心领域,包括基础语法、面向对象编程、模板、异常处理、STL(标准模板库)等。 我们来探讨C++的基础语法。C++是C语言的增强版,它保留了C语言的高效性和灵活性,并引入了类、对象和继承等面向对象编程概念。基础语法包括变量声明、数据类型、运算符、控制结构(如if语句、for循环、while循环)、函数的定义和调用等。在实例中,你可能会遇到如何编写简单的程序,如计算两个数的和,或者实现一个简单的猜数字游戏。 C++的面向对象编程是其一大特色。通过类和对象,你可以构建复杂的软件系统。类是对象的蓝图,它定义了对象的属性和行为。实例化一个类,就是创建一个具体的对象。继承允许你创建新的类,这些类从现有的类派生,共享其属性和方法,同时可以添加新的功能。多态性是面向对象的另一个关键特性,它使得不同类型的对象可以对同一消息作出不同的响应。这些概念在实例中会以各种形式展现,例如设计一个图形界面的类层次,或实现一个简单的模拟游戏。 接下来是模板,C++的模板功能让代码更加通用,可以处理不同类型的数据。模板分为函数模板和类模板,前者可以创建泛型函数,后者可以创建泛型类。通过模板,你可以编写出高效且灵活的代码,比如实现一个通用的排序算法。 异常处理是C++中用于处理程序运行时错误的机制。当程序出现异常情况时,可以抛出一个异常,然后在适当的点捕获并处理这个异常。这使得代码能够优雅地处理错误,而不是让程序崩溃。实例中可能会有涉及文件操作或网络通信时可能出现的异常处理示例。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值