# Loj #139

* 树链剖分模板题
* 由于存在换根操作
* 对所有关于节点 u 的修改和查询操作进行分类讨论
* 若 Root 在 u 的子树中，则不处理 u 所在的 Root 的那颗子树
* 否则不会有影响
* 寻找 Root 所在的那颗子树的根可以用倍增求

#include <bits/stdc++.h>

const int N = 1e5 + 10;

#define LL long long

int topp[N], fa[N], size[N], son[N], deep[N], tree[N], lst[N], rst[N], bef[N], data[N];
int f[N][30];
int Tree;
LL W[N << 2], F[N << 2], S[N << 2];
struct Node {
int u, v, nxt;
} G[N << 1];
int n, m, Root;

int opt, T;

#define gc getchar()

int x = 0; char c = gc;
while(c < '0' || c > '9') c = gc;
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc;
return x;
}

void Dfs_1(int u, int f_, int dep) {
fa[u] = f_, deep[u] = dep, size[u] = 1;
for(int i = head[u]; ~ i; i = G[i].nxt) {
int v = G[i].v;
if(v == f_) continue;
f[v][0] = u;
Dfs_1(v, u, dep + 1);
size[u] += size[v];
if(size[son[u]] < size[v]) son[u] = v;
}
}

void Dfs_2(int u, int tp) {
topp[u] = tp, tree[u] = ++ Tree, bef[Tree] = u, lst[u] = Tree;
if(!son[u]) {
rst[u] = Tree; return ;
}
Dfs_2(son[u], tp);
for(int i = head[u]; ~ i; i = G[i].nxt) {
int v = G[i].v;
if(v != fa[u] && v != son[u]) Dfs_2(v, v);
}
rst[u] = Tree;
}

void Before() {
for(int i = 1; (1 << i) <= n; i ++)
for(int j = 1; j <= n; j ++)
if(f[j][i - 1]) f[j][i] = f[f[j][i - 1]][i - 1];
}

#define lson jd << 1
#define rson jd << 1 | 1

void Build_tree(int l, int r, int jd) {
S[jd] = (r - l + 1);
if(l == r) {
W[jd] = data[bef[l]];
return ;
}
int mid = (l + r) >> 1;
Build_tree(l, mid, lson);
Build_tree(mid + 1, r, rson);
W[jd] = W[lson] + W[rson];
}

void Pushdown(int jd) {
if(!F[jd]) return ;
F[lson] += F[jd];
F[rson] += F[jd];
W[lson] += (S[lson] * F[jd]);
W[rson] += (S[rson] * F[jd]);
F[jd] = 0;
}

void Sec_G(int l, int r, int jd, int x, int y, int num) {
if(x <= l && r <= y) {
F[jd] += num;
W[jd] += (S[jd] * num);
return ;
}
Pushdown(jd);
int mid = (l + r) >> 1;
if(x <= mid) Sec_G(l, mid, lson, x, y, num);
if(y >  mid) Sec_G(mid + 1, r, rson, x, y, num);
W[jd] = W[lson] + W[rson];
}

void Sec_G_imp(int x, int y, int num) {
int tpx = topp[x], tpy = topp[y];
while(tpx != tpy) {
if(deep[tpx] < deep[tpy]) std:: swap(tpx, tpy), std:: swap(x, y);
Sec_G(1, n, 1, tree[tpx], tree[x], num);
x = fa[tpx];
tpx = topp[x];
}
if(deep[x] < deep[y]) std:: swap(x, y);
Sec_G(1, n, 1, tree[y], tree[x], num);
return ;
}

inline int Find(int x, int y) {
int dy = deep[y], dx = deep[x];
int del = deep[y] - deep[x] - 1;
for(int i = 0; (1 << i) <= del; i ++)
if(del & (1 << i)) y = f[y][i];
return y;
}

void Sec_A(int l, int r, int jd, int x, int y) {
if(x <= l && r <= y) {
return ;
}
Pushdown(jd);
int mid = (l + r) >> 1;
if(x <= mid) Sec_A(l, mid, lson, x, y);
if(y > mid)  Sec_A(mid + 1, r, rson, x, y);
}

LL Sec_A_imp(int x, int y) {
int tpx = topp[x], tpy = topp[y];
LL ret = 0;
while(tpx != tpy) {
if(deep[tpx] < deep[tpy]) std:: swap(tpx, tpy), std:: swap(x, y);
Sec_A(1, n, 1, tree[tpx], tree[x]);
x = fa[tpx];
tpx = topp[x];
}
if(deep[x] < deep[y]) std:: swap(x, y);
Sec_A(1, n, 1, tree[y], tree[x]);
return ret;
}

int main() {
Root = 1;
for(int i = 1; i <= n; i ++) head[i] = -1;
for(int i = 1; i <= n; i ++) data[i] = read();
for(int i = 1; i < n; i ++) {
}
Dfs_1(1, 0, 1);
Dfs_2(1, 1);
Build_tree(1, n, 1);
Before();
for(T = 1; T <= t; T ++) {
if(opt == 1) Root = read();
else if(opt == 2) {
Sec_G_imp(u, v, x);
} else if(opt == 3) {
if(Root == u) {
Sec_G(1, n, 1, 1, n, x);
continue;
}
if(lst[u] <= tree[Root] && tree[Root] <= rst[u]) {
Sec_G(1, n, 1, 1, n, x);
int Use_son = Find(u, Root);
Sec_G(1, n, 1, lst[Use_son], rst[Use_son], -x);
} else Sec_G(1, n, 1, lst[u], rst[u], x);
} else if(opt == 4) {
printf("%lld\n", Sec_A_imp(x, y));
} else {
if(Root == u) {
Sec_A(1, n, 1, 1, n);
continue;
}
LL Now_ans = 0;
if(lst[u] <= tree[Root] && tree[Root] <= rst[u]) {
Sec_A(1, n, 1, 1, n);
int Use_son = Find(u, Root);
Sec_A(1, n, 1, lst[Use_son], rst[Use_son]);
} else {
}