# P3178 [HAOI2015]树上操作

有一棵点数为 N 的树，以点 1 为根，且树点有边权。然后有 M 个操作，分为三种：

https://www.bilibili.com/video/BV1xE411j7WF?from=search&seid=7017680147370733736

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long
const int N = 1e5+11;

struct Edge {
int next,to;
} edge[N<<1];

int n,m;

/*
cnt = 第二次dfs当前映射的编号
dep(x) = x节点深度
fa(x) = x节点父亲
son(x) = x节点的重儿子
size(x) = x节点的大小
num(x) = x节点输入的原始值
id(x) = x的第二次编号
val(x) = x在新编号下对应的原节点
top(x) = x节点所在链的顶端
*/

int cnt,dep[N],fa[N],son[N],size[N],num[N];
int val[N],id[N],top[N];
ll res;

struct seg {
seg *ls, *rs;
#define Len (1 << 16)
inline void* operator new(size_t) {
static seg *mempool, *c;
if (mempool == c)
mempool = (c = new seg[Len]) + Len;
c -> ls = c -> rs = NULL;
c -> sum = c -> add = c -> len = 0;
return c++;
}
#undef Len    //取消宏定义

inline void update() {
sum = ls -> sum + rs -> sum;
}
inline void push() {
ls -> sum += add * ls -> len, rs -> sum += add * rs -> len;
}

#define mid (l + r >> 1)
void build(int l, int r) {
if (l == r) {
sum = num[val[l]];
len = 1;
return;
}
(ls = new seg) -> build(l, mid);
(rs = new seg) -> build(mid + 1, r);
len = r - l + 1;
update();
}

void modify(int l, int r, int L, int R, ll del) {
if (L <= l && r <= R) {
sum += len * del;
return;
}
push();
if (L <= mid) ls -> modify(l, mid, L, R, del);
if (mid < R) rs -> modify(mid + 1, r, L, R, del);
update();
}

ll query(int l, int r, int L, int R) {
if (L <= l && r <= R) return sum;
push();
ll res = 0;
if (L <= mid) res += ls -> query(l, mid, L, R);
if (mid < R) res += rs -> query(mid + 1, r, L, R);
update();
return res;
}
#undef mid
} *T;

edge[num_edge].to=to;
}

void dfs1(int u,int f) {
dep[u]=dep[f]+1;  //记录深度
fa[u]=f;  //记录父亲节点
size[u]=1;  //子树大小
int &v=edge[i].to;
if(v==f) continue;
dfs1(v,u);
size[u] += size[v];
if(size[v]>size[son[u]]) son[u] = v;  //记录重儿子
}
}
void dfs2(int u,int tp) {
id[u]=++cnt;  //dfs序：u节点的第二个编号
val[cnt]=u;   //新编号对应的原节点
top[u]=tp;     //u节点所在链的顶点
if(!son[u]) return;
dfs2(son[u],tp);
int &v=edge[i].to;
if(id[v]) continue;
dfs2(v,v);
}
return;
}

ll ans=0ll;
while(top[x]!=top[y]) {
if(dep[top[x]]<dep[top[y]]) swap(x,y);
res=0;
res += T-> query(1,n,id[top[x]],id[x]);
ans += res;
x = fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
res = 0;
res += T->query(1,n,id[x],id[y]);
ans += res;
return ans;
}
int main()
{
T = new seg;  //定义一颗线段树
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++) scanf("%d",&num[i]);   //读入初始节点权值
for(int i=1,x,y; i<n;i++) {
scanf("%d%d",&x,&y);   //建树
}
dfs1(1,0);
dfs2(1,1);
T->build(1,n);  //建立线段树
for(int i=1,opt,x,y; i<=m; ++i) {
scanf("%d",&opt);
if(opt==1) {
scanf("%d%d",&x,&y);
T->modify(1,n,id[x],id[x],y);  //x节点加y
} else if(opt==2) {
scanf("%d%d",&x,&y);
T->modify(1,n,id[x],id[x]+size[x]-1,y);  //以x节点为根的子树每个节点加y
} else if(opt==3) {
scanf("%d",&x);
}
}
return 0;
}

04-29 71
07-15 44

02-04 101
08-22 48
08-18 589
04-29 372
02-22 193