思路:如果是对区间 [ l , r ] [l,r] [l,r]进行操作的话,对于 x ∈ [ l , r ] , w [ x ] + = ( x − l + 1 ) 2 x∈[l,r],w[x]+=(x-l+1)^2 x∈[l,r],w[x]+=(x−l+1)2,
令 k = l − 1 k=l-1 k=l−1,那么 w [ x ] + = ( x − k ) 2 w[x]+=(x-k)^2 w[x]+=(x−k)2,把括号拆开 − > x 2 − 2 ∗ x ∗ k + k 2 ->x^2-2*x*k+k^2 −>x2−2∗x∗k+k2,
那么就需要维护3个对于 t t t次修改后的线段树 ∑ i = 1 t 1 \sum_{i=1}^{t}{1} ∑i=1t1, ∑ i = 1 t k \sum_{i=1}^{t}{k} ∑i=1tk, ∑ i = 1 t k 2 \sum_{i=1}^{t}{k^2} ∑i=1tk2
在查询 x x x时就返回 x 2 ∑ i = 1 t 1 − 2 x ∑ i = 1 t k + ∑ i = 1 t k 2 x^2\sum_{i=1}^{t}{1} -2x\sum_{i=1}^{t}{k}+\sum_{i=1}^{t}{k^2} x2∑i=1t1−2x∑i=1tk+∑i=1tk2
在树上进行操作需要先树链剖分,把一条路径分成若干条连续区间
要注意的是在modify每个区间时,是此区间的左端点为准
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<vector>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
vector<int> v[N];
int n, x, y, q, a, b;
int dep[N], id[N], son[N], idx, sz[N], top[N], f[N], op;
void dfs1(int u, int fa) {
dep[u] = dep[fa] + 1, sz[u] = 1, f[u] = fa;
for (auto i:v[u]) {
if (i == fa)continue;
dfs1(i, u);
sz[u] += sz[i];
if (sz[son[u]] < sz[i])son[u] = i;
}
}
void dfs2(int u, int t) {
top[u] = t, id[u] = ++idx;
if (!son[u])return;
dfs2(son[u], t);
for (auto i:v[u]) {
if (i == f[u] || i == son[u])continue;
dfs2(i, i);
}
}
struct segtree {
struct node {
ll l, r;
ll sum, lazy;
} tr[N << 2];
void pushup(int u) {
tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
}
void pushdown(int u) {
tr[u << 1].lazy += tr[u].lazy, tr[u << 1 | 1].lazy += tr[u].lazy;
tr[u << 1].sum += tr[u].lazy * (tr[u << 1].r - tr[u << 1].l + 1);
tr[u << 1 | 1].sum += tr[u].lazy * (tr[u << 1 | 1].r - tr[u << 1 | 1].l + 1);
tr[u].lazy = 0;
}
void build(int u, int l, int r) {
tr[u] = {l, r, 0, 0};
if (l == r)return;
int mid = l + r >> 1;
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1, r);
pushup(u);
}
void modify(int u, int l, int r, ll k) {
if (l <= tr[u].l && r >= tr[u].r) {
tr[u].sum += k * (tr[u].r - tr[u].l + 1);
tr[u].lazy += k;
return;
}
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
if (l <= mid)modify(u << 1, l, r, k);
if (r > mid)modify(u << 1 | 1, l, r, k);
pushup(u);
}
ll query(int u, int x) {
if (tr[u].l == tr[u].r && tr[u].l == x)
return tr[u].sum;
int mid = tr[u].l + tr[u].r >> 1;
pushdown(u);
if (x <= mid)return query(u << 1, x);
return query(u << 1 | 1, x);
}
} s1, s2, s3;
int lca(int a, int b) {
while (top[a] != top[b]) {
if (dep[top[a]] >= dep[top[b]])a = f[top[a]];
else b = f[top[b]];
}
if (dep[a] < dep[b])return a;
return b;
}
void modify_path(int a, int b) {
int p = lca(a, b);
int l = 1, r = dep[a] + dep[b] - 2 * dep[p] + 1;
while (top[a] != top[b]) {
if (dep[top[a]] > dep[top[b]]) {
ll add = id[a] + l;
l += dep[a] - dep[top[a]] + 1;
s1.modify(1, id[top[a]], id[a], 1);
s2.modify(1, id[top[a]], id[a], add);
s3.modify(1, id[top[a]], id[a], add * add);
a = f[top[a]];
} else {
int len = dep[b] - dep[top[b]] + 1;
ll add = id[top[b]] - (r - len - 1);
r -= len;
s1.modify(1, id[top[b]], id[b], 1);
s2.modify(1, id[top[b]], id[b], add);
s3.modify(1, id[top[b]], id[b], add * add);
b = f[top[b]];
}
}
if (dep[a] > dep[b]) {
ll add = id[a] + l;
s1.modify(1, id[b], id[a], 1);
s2.modify(1, id[b], id[a], add);
s3.modify(1, id[b], id[a], add * add);
} else {
int len = dep[b] - dep[a] + 1;
ll add = id[a] - (r - len + 1);
s1.modify(1, id[a], id[b], 1);
s2.modify(1, id[a], id[b], add);
s3.modify(1, id[a], id[b], add * add);
}
}
int main() {
scanf("%d", &n);
for (int i = 1; i < n; i++) {
scanf("%d%d", &a, &b);
v[a].push_back(b);
v[b].push_back(a);
}
dfs1(1, -1);
dfs2(1, 1);
s1.build(1, 1, n), s2.build(1, 1, n), s3.build(1, 1, n);
scanf("%d", &q);
while (q--) {
scanf("%d%d", &op, &a);
if (op == 1) {
scanf("%d", &b);
modify_path(a, b);
} else {
ll x = s1.query(1, id[a]);
ll y = s2.query(1, id[a]);
ll z = s3.query(1, id[a]);
printf("%lld\n", z - 2ll * id[a] * y + x * id[a] * id[a]);
}
}
return 0;
}