题目大意:
就是给你一颗树
树上每个点的初始权值为
0
0
0
现在有两个操作
- < 1 , a , b > <1,a,b> <1,a,b>对于 a a a到 b b b路径上所有点加上到 a a a的距离的平方和
- < 2 , a > <2,a> <2,a>询问 a a a点的权值
解题思路:
-
对于树链上的修改问题我们很容易想到树链剖分
-
但是怎么对于每个点距离 a a a的距离不一样那么累加的权值也不一样怎么办?
-
首先我们知道对于树链剖分上面的线段树是用 时 间 戳 d f n 时间戳dfn 时间戳dfn进行区间划分的,那么我们就可以往 d f n dfn dfn上面想
-
我们观察一下下面的图片就是 < a , b > <a,b> <a,b>的路径上面有两种情况 a − > l c a a->lca a−>lca和 l c a − > b lca->b lca−>b
-
现在假设我们要得到某个点得值那么只能是靠 d f n [ x ] dfn[x] dfn[x]去计算答案
d i s t a n c e ( a , x ) 2 = ( d f n [ x ] − ? ) 2 distance(a,x)^2=(dfn[x]-?)^2 distance(a,x)2=(dfn[x]−?)2 -
现在就是要求这个问号是什么?
对于 a − > l c a a->lca a−>lca的情况 -
我们知道对于 [ d f n [ t o p [ x ] ] , d f n [ x ] ] [dfn[top[x]],dfn[x]] [dfn[top[x]],dfn[x]]这是一段连续的区间
-
对于里面的任意一个点 x ′ x' x′我们可以 ( d f n [ x ′ ] − d f n [ x ] ) 2 (dfn[x']-dfn[x])^2 (dfn[x′]−dfn[x])2
-
但是我们知道树链剖分是一段一段的跳的那么上面的那个式子还得加上 a 和 x 之 间 有 多 少 个 点 a和x之间有多少个点 a和x之间有多少个点?
-
但是注意 ( d f n [ x ′ ] − d f n [ x ] ) 2 (dfn[x']-dfn[x])^2 (dfn[x′]−dfn[x])2里面是负数所以你要减掉点数
-
( d f n [ x ′ ] − d f n [ x ] − p o i n t ′ s n u m b r e b e t w e e n x a n d a ) 2 (dfn[x']-dfn[x]-point's \; numbre\;between\;x\;and\;a)^2 (dfn[x′]−dfn[x]−point′snumbrebetweenxanda)2
-
( d f n [ x ′ ] − ( d f n [ x ] + p o i n t ′ s n u m b r e b e t w e e n x a n d a ) ) 2 (dfn[x']-(dfn[x]+point's \; numbre\;between\;x\;and\;a))^2 (dfn[x′]−(dfn[x]+point′snumbrebetweenxanda))2
-
n u m = ( d f n [ x ] + p o i n t ′ s n u m b r e b e t w e e n x a n d a ) num=(dfn[x]+point's \; numbre\;between\;x\;and\;a) num=(dfn[x]+point′snumbrebetweenxanda)
-
( d f n [ x ′ ] − n u m ) 2 = d f n [ x ′ ] 2 − 2 ∗ n u m ∗ d f n [ x ′ ] + n u m 2 (dfn[x']-num)^2=dfn[x']^2-2*num*dfn[x']+num^2 (dfn[x′]−num)2=dfn[x′]2−2∗num∗dfn[x′]+num2
-
那么我们就可以用3个线段树去维护这3项的系数 1 , 2 ∗ n u m , n u m 2 1,2*num,num^2 1,2∗num,num2因为对于同一个区间 n u m num num
是一样的
对于 b − > l c a b->lca b−>lca的情况 -
这里是 ( d f n [ x ′ ] − d f n [ t o p [ x ′ ] ] ) 2 (dfn[x']-dfn[top[x']])^2 (dfn[x′]−dfn[top[x′]])2注意这里面 d f n [ x ′ ] − d f n [ t o p [ x ′ ] ] dfn[x']-dfn[top[x']] dfn[x′]−dfn[top[x′]]是大于0的
-
那么和上面同理但是计算距离的时候你要算出 t o p [ x ′ ] 到 a 的 距 离 top[x']到a的距离 top[x′]到a的距离
AC代码:
#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define f first
#define s second
#define endl '\n'
using namespace std;
const int N = 2e6 + 10, mod = 1e9 + 9;
const int maxn = 500010;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x)
{
x = 0;char ch = getchar();ll f = 1;
while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args)
{
read(first);
read(args...);
}
int T;
int n, m;
struct node {
int to, next;
}e[N];
int head[N], cnt;
inline void add(int from, int to) {
e[cnt] = {to,head[from]};
head[from] = cnt ++;
}
//...............................
int fa[N], dep[N], siz[N], son[N];
inline void dfs1(int u, int f) {
fa[u] = f, dep[u] = dep[f] + 1, siz[u] = 1;
int max_siz = -1;
for(int i = head[u]; ~i; i = e[i].next) {
int v = e[i].to;
if(v == f) continue;
dfs1(v,u);
siz[u] += siz[v];
if(siz[v] > max_siz) {
son[u] = v;
max_siz = siz[v];
}
}
}
ll tim, dfn[N], top[N];
inline void dfs2(int u, int t) {
dfn[u] = ++ tim, top[u] = t;
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);
}
}
struct Segtree {
ll tr[maxn], lazy[maxn];
void add(int rt , int l, int r, int posL, int posR, ll val) {
if(posL <= l && posR >= r) {
tr[rt] += val;
lazy[rt] += val;
return;
}
if(posL <= mid) add(Lson,posL,posR,val);
if(posR > mid) add(Rson,posL,posR,val);
}
inline void pushdown(int rt) {
if(lazy[rt]) {
lazy[rt << 1] += lazy[rt];
lazy[rt << 1|1] += lazy[rt];
tr[rt << 1] += lazy[rt];
tr[rt << 1|1] += lazy[rt];
lazy[rt] = 0;
}
}
ll ask(int rt, int l, int r, int pos) {
if(l == r) return tr[rt];
pushdown(rt);
if(pos <= mid) return ask(Lson,pos);
else return ask(Rson,pos);
}
}seg[3];
int LCA(int x,int y)
{
for(;top[x]!=top[y];dep[top[x]]>dep[top[y]]?x=fa[top[x]]:y=fa[top[y]]);
return dep[x]<dep[y]?x:y;
}
inline void tree_change(int a, int b) {
int lca = LCA(a,b);
int len = dep[a] + dep[b] - 2 * dep[lca] + 1;
int up = 1, down = 0;
// cout << top[a] << " " << top[b] <<endl;
while(top[a] != top[b]) {
if(dep[top[a]] > dep[top[b]]) {
ll k = dfn[a] + up;
// cout << k << endl;
seg[0].add(1,1,n,dfn[top[a]],dfn[a],k*k);
seg[1].add(1,1,n,dfn[top[a]],dfn[a],2*k);
seg[2].add(1,1,n,dfn[top[a]],dfn[a],1);
up += dep[a] - dep[top[a]] + 1;
a = fa[top[a]];
} else {
ll k = dfn[top[b]] - 1 - (len - (dep[b] - dep[top[b]] + 1) - down);//后面计算距离
seg[0].add(1,1,n,dfn[top[b]],dfn[b],k*k);
seg[1].add(1,1,n,dfn[top[b]],dfn[b],2*k);
seg[2].add(1,1,n,dfn[top[b]],dfn[b],1);
down += dep[b] - dep[top[b]] + 1;
b = fa[top[b]];
}
}
if(dep[a] > dep[b]) {
ll k = dfn[a] + up;
seg[0].add(1,1,n,dfn[b],dfn[a],k*k);
seg[1].add(1,1,n,dfn[b],dfn[a],2*k);
seg[2].add(1,1,n,dfn[b],dfn[a],1);
} else {
ll k = dfn[a] - 1 - (len - (dep[b] - dep[a] + 1) - down);
// cout << k <<endl;
seg[0].add(1,1,n,dfn[a],dfn[b],k*k);
seg[1].add(1,1,n,dfn[a],dfn[b],2*k);
seg[2].add(1,1,n,dfn[a],dfn[b],1);
}
}
inline ll ask(int pos) {
return 1ll * dfn[pos] * dfn[pos] * seg[2].ask(1,1,n,dfn[pos]) - 1ll * dfn[pos] * seg[1].ask(1,1,n,dfn[pos]) + 1ll * seg[0].ask(1,1,n,dfn[pos]);
}
int main() {
//IOS;
ms(head,-1);
cin >> n;
for(int i = 1; i < n; ++ i) {
int u, v;
cin >> u >> v;
add(u,v);
add(v,u);
}
dfs1(1,0);
dfs2(1,0);
// for(int i = 1; i <= n; ++ i) cout << dfn[i] << endl;
int m;
cin >> m;
while(m --) {
int op;
cin >> op;
if(op == 1) {
int a, b;
cin >> a >> b;
tree_change(a,b);
} else {
int pos;
cin >> pos;
cout << ask(pos) << endl;
}
}
return 0;
}
/*
9
2 1
3 1
4 2
5 2
6 4
7 3
8 3
9 3
2
1 8 4
2 1
5
2 1
3 2
4 1
5 4
2
1 1 3
2 1
17
1 1 1
2 1
1 4 3
2 1
1 2 4
2 1
1 1 3
2 1
1 2 4
2 1
1 4 1
2 1
1 3 2
2 4
1 4 5
2 2
2 2
*/