题目大意
给你一棵树,有两种操作
1、将路径
u
u
u 到
v
v
v 上的点按照与
u
u
u 的距离,加上
1
4
9
⋯
i
2
1 \ 4 \ 9 \cdots i^2
1 4 9⋯i2
2、问节点
x
x
x 的值为多少
解题思路
树链剖分 + 线段树
首先我们可以进行一个树链剖分,这样便于处理操作1。
对于操作1,我们首先找出
u
u
u 与
v
v
v 的
l
c
a
lca
lca
对于树链
u
u
u 到
l
c
a
lca
lca,我们每个节点所加的值为
(
d
e
p
[
t
]
−
d
e
p
[
u
]
+
1
)
2
(dep[t] - dep[u] + 1)^2
(dep[t]−dep[u]+1)2
化简一下
d
e
p
[
t
]
2
−
2
×
(
d
e
p
[
u
]
−
1
)
×
d
e
p
[
t
]
+
(
d
e
p
[
u
]
−
1
)
2
dep[t]^2 - 2\times (dep[u] - 1) \times dep[t] + (dep[u] - 1)^2
dep[t]2−2×(dep[u]−1)×dep[t]+(dep[u]−1)2
我们可以开三个线段树维护这三个值,我们发现,对于每个点的
d
e
p
[
t
]
dep[t]
dep[t] 是确定的,所以我们只需要记录一下这个多项式的系数即可。
对于树链
v
v
v 到
l
c
a
lca
lca,每个节点所加的值为
(
d
e
p
[
t
]
−
(
2
×
d
e
p
[
l
c
a
]
−
d
e
p
[
x
]
−
1
)
)
2
(dep[t] - (2\times dep[lca] - dep[x] - 1))^2
(dep[t]−(2×dep[lca]−dep[x]−1))2
化简一下
d
e
p
[
t
]
2
−
2
×
(
2
×
d
e
p
[
l
c
a
]
−
d
e
p
[
x
]
−
1
)
×
d
e
p
[
t
]
+
(
2
×
d
e
p
[
l
c
a
]
−
d
e
p
[
x
]
−
1
)
2
dep[t]^2 - 2\times (2\times dep[lca] - dep[x] - 1) \times dep[t] + (2\times dep[lca] - dep[x] - 1)^2
dep[t]2−2×(2×dep[lca]−dep[x]−1)×dep[t]+(2×dep[lca]−dep[x]−1)2
Code
#include <bits/stdc++.h>
#define ll long long
#define qc ios::sync_with_stdio(false); cin.tie(0);cout.tie(0)
#define fi first
#define se second
#define PII pair<int, int>
#define PLL pair<ll, ll>
#define pb push_back
using namespace std;
const int MAXN = 2e5 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1e9 + 7;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
int n, m;
int fa[MAXN], sz[MAXN], top[MAXN], dfn[MAXN], son[MAXN], dep[MAXN];
int tim;
struct Tree{
struct T{
int l, r;
ll sum, add;
}tree[MAXN << 2];
void pushup(int rt){
tree[rt].sum = tree[rt << 1].sum + tree[rt << 1 | 1].sum;
}
void build(int l, int r, int rt){
tree[rt].l = l;
tree[rt].r = r;
tree[rt].add = 0;
tree[rt].sum = 0;
if(l == r) return ;
int m = (l + r) >> 1;
build(l, m, rt << 1);
build(m+1, r, rt << 1 | 1);
}
void pushdown(int rt){
if(tree[rt].add){
tree[rt << 1].add += tree[rt].add;
tree[rt << 1].sum += (tree[rt << 1].r - tree[rt << 1].l + 1) * tree[rt].add;
tree[rt << 1 | 1].add += tree[rt].add;
tree[rt << 1 | 1].sum += (tree[rt << 1 | 1].r - tree[rt << 1 | 1].l + 1) * tree[rt].add;
tree[rt].add = 0;
}
}
ll query(int L, int R, int rt){
if(L <= tree[rt].l && tree[rt].r <= R)
return tree[rt].sum;
pushdown(rt);
int m = (tree[rt].l + tree[rt].r) >> 1;
ll ret = 0;
if(L <= m)
ret += query(L, R, rt << 1);
if(m < R)
ret += query(L, R, rt << 1 | 1);
return ret;
}
void update(int L, int R, ll x, int rt){
if(L <= tree[rt].l && tree[rt].r <= R){
tree[rt].sum += (tree[rt].r - tree[rt].l + 1) * x;
tree[rt].add += x;
return ;
}
pushdown(rt);
int m = (tree[rt].l + tree[rt].r) >> 1;
if(L <= m)
update(L, R, x, rt << 1);
if(m < R)
update(L, R, x, rt << 1 | 1);
pushup(rt);
}
}tree[3];
int head[MAXN];
struct edge{
int to, next;
}e[MAXN << 1];
int tot;
void init(){
memset(head, -1, sizeof(head));
tot = 0;
}
void add(int u, int v){
e[tot].to = v;
e[tot].next = head[u];
head[u] = tot++;
}
void dfs1(int x, int f){
dep[x] = dep[f] + 1;
sz[x] = 1;
fa[x] = f;
int maxx = 0;
for(int i = head[x]; ~i; i = e[i].next){
int v = e[i].to;
if(v == f) continue;
dfs1(v, x);
sz[x] += sz[v];
if(sz[v] > maxx){
maxx = sz[v];
son[x] = v;
}
}
}
void dfs2(int u, int t ){
top[u] = t;
dfn[u] = ++tim;
if(!son[u]) return;
dfs2(son[u], t);
for(int i = head[u]; ~i; i = e[i].next){
int v = e[i].to;
if(v == fa[u] || v == son[u]) continue;
dfs2(v, v);
}
}
int LCA(int x, int y){
while(top[x] != top[y]){
if(dep[top[x]] > dep[top[y]]) swap(x, y);
y = top[y];
y = fa[y];
}
return dep[x] > dep[y] ? y : x;
}
void slove(int x, int y){
int lca = LCA(x, y);
ll p = dep[x] + 1;
int xx = x;
while(top[x] != top[lca]){
tree[0].update(dfn[top[x]], dfn[x], 1, 1);
tree[1].update(dfn[top[x]], dfn[x], -2*p, 1);
tree[2].update(dfn[top[x]], dfn[x], p*p, 1);
x = fa[top[x]];
}
tree[0].update(dfn[lca], dfn[x], 1, 1);
tree[1].update(dfn[lca], dfn[x], -2*p, 1);
tree[2].update(dfn[lca], dfn[x], p*p, 1);
tree[0].update(dfn[lca], dfn[lca], -1, 1);
tree[1].update(dfn[lca], dfn[lca], 2*p, 1);
tree[2].update(dfn[lca], dfn[lca], -p*p, 1);
p = 2*dep[lca] - dep[xx] - 1;
while(top[y] != top[lca]){
tree[0].update(dfn[top[y]], dfn[y], 1, 1);
tree[1].update(dfn[top[y]], dfn[y], -2*p, 1);
tree[2].update(dfn[top[y]], dfn[y], p*p, 1);
y = fa[top[y]];
}
tree[0].update(dfn[lca], dfn[y], 1, 1);
tree[1].update(dfn[lca], dfn[y], -2*p, 1);
tree[2].update(dfn[lca], dfn[y], p*p, 1);
}
ll query(int x){
return dep[x] * dep[x] * tree[0].query(dfn[x], dfn[x], 1) + dep[x] * tree[1].query(dfn[x], dfn[x], 1) + tree[2].query(dfn[x], dfn[x], 1);
}
void solve(){
init();
cin >> n;
for (int i = 1; i <= n-1; ++i){
int u, v;
cin >> u >> v;
add(u, v);
add(v, u);
}
dfs1(1, 1);
dfs2(1, 1);
for (int i = 0; i <= 2; ++i){
tree[i].build(1, n, 1);
}
int q;
cin >> q;
while(q--){
int op;
cin >> op;
if(op == 1){
int u, v;
cin >> u >> v;
slove(u, v);
}
else{
int x;
cin >> x;
cout << query(x) << "\n";
}
}
}
int main()
{
#ifdef ONLINE_JUDGE
#else
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
qc;
int T;
// cin >> T;
T = 1;
while(T--){
solve();
}
return 0;
}