树链剖分模板

讲解移步:
树链剖分
这里以[树上操作]这题为例:
code:

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
using namespace std;
#define MAXN 100005
#pragma GCC optomizer(2)
#define ll long long
using namespace std;
//a[]原数据 ans[]线段树 tag[]懒惰标记 
ll in[MAXN],deep[MAXN],fa[MAXN],size[MAXN],top[MAXN],son[MAXN],sum;
unsigned ll n,m,a[MAXN],ans[MAXN<<2],tag[MAXN<<2],head[MAXN<<1],cnt,num[MAXN<<1];
struct node{
	int to;
	int from;
}edge[MAXN<<1];
inline ll ls(ll x)
{
    return x<<1;
}
inline ll rs(ll x)
{
    return x<<1|1;
}
inline void push_up(ll p)
{
    ans[p]=ans[ls(p)]+ans[rs(p)];
}
void build(ll p,ll l,ll r)
{
    tag[p]=0;
    if(l==r){ans[p]=num[l];return ;}
    ll mid=(l+r)>>1;
    build(ls(p),l,mid);
    build(rs(p),mid+1,r);
    push_up(p);
} 
inline void f(ll p,ll l,ll r,ll k)
{
    tag[p]=tag[p]+k;
    ans[p]=ans[p]+k*(r-l+1);
}
inline void push_down(ll p,ll l,ll r)
{
	if(tag[p]){
		ll mid=(l+r)>>1;
	    f(ls(p),l,mid,tag[p]);
	    f(rs(p),mid+1,r,tag[p]);
	    tag[p]=0;
	}     
}
inline void update(ll nl,ll nr,ll l,ll r,ll p,ll k)
{
    if(nl<=l&&r<=nr)
    {
        ans[p]+=k*(r-l+1);
        tag[p]+=k;
        return ;
    }
    push_down(p,l,r);
    ll mid=(l+r)>>1;
    if(nl<=mid)update(nl,nr,l,mid,ls(p),k);
    if(nr>mid) update(nl,nr,mid+1,r,rs(p),k);
    push_up(p);
}
ll query(ll q_x,ll q_y,ll l,ll r,ll p)
{
    ll res=0;
//    cout<<l<<r<<"error"<<endl;
    if(q_x<=l&&r<=q_y)return ans[p];
    ll mid=(l+r)>>1;
    
    push_down(p,l,r);
    
    if(q_x<=mid)res+=query(q_x,q_y,l,mid,ls(p));
    
    if(q_y>mid) res+=query(q_x,q_y,mid+1,r,rs(p));
    
    return res;
}
void add(int u,int v){
	cnt++;
	edge[cnt].to = v;
	edge[cnt].from = head[u];
	head[u] = cnt;
}
void dfs1(int x,int f,int dep)
{
	deep[x] = dep;
	fa[x] = f;
	size[x] =1;
	int max_son = -1;
	for(int i = head[x];i;i=edge[i].from)
	{
		int to = edge[i].to;
		if(to==f) continue;
		dfs1(to,x,dep+1);
		size[x]+=size[to];
		if(size[to]>max_son){
			son[x] = to;
			max_son = size[to];
		}
	}
}
void dfs2(int x,int topf){
	in[x] = ++sum;
	num[in[x]] = a[x];
	top[x] = topf;
	if(!son[x]) return;
	dfs2(son[x],topf);
	for(int i = head[x];i;i=edge[i].from)
	{
		int to = edge[i].to;
		if(to==fa[x])continue;
		if(to==son[x])continue;
		dfs2(to,to);
	}	
}
ll qrange(int x,int y){
	ll ans = 0;
	while(top[x]!=top[y]){
		if(deep[top[x]]<deep[top[y]])swap(x,y);
		
		ans+=query(in[top[x]],in[x],1,n,1);
		
		x = fa[top[x]];
	}
	if(deep[x]>deep[y])swap(x,y);
	ans+=query(in[x],in[y],1,n,1);
	return ans;
}
ll updrange(int x,int y,int k)
{
	while(top[x]!=top[y]){
		if(deep[x]<deep[y]){
			swap(x,y);
		}
		update(in[top[x]],in[x],1,n,1,k);
		x = fa[top[x]];
	}
	if(deep[x]>deep[y])swap(x,y);
	update(in[x],in[y],1,n,1,k);
}
ll qson(int x){
	return query(in[x],in[x]+size[x]-1,1,n,1);
}
void updson(int x,int k){
	update(in[x],in[x]+size[x]-1,1,n,1,k);
}

int main(){
	
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	for(int i=1;i<n;i++)
	{
		int u,v;
		cin>>u>>v;
		add(u,v);
		add(v,u);
	}
	
	dfs1(1,0,1);
	
	dfs2(1,1);
	
	build(1,1,n);
	
	for(int i=1;i<=m;i++)
	{
		int set;
		cin>>set;
		if(set==1){
			int x,a;
			cin>>x>>a;
			updrange(x,x,a);
		}
		if(set==2){
			int x,a;
			cin>>x>>a;
			updson(x,a);
		}
		if(set==3){
			int x;
			cin>>x;
			cout<<qrange(1,x)<<endl;
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值