讲解移步:
树链剖分
这里以[树上操作]这题为例:
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;
}
}
}