题意:
给你
n
n
n个点的一颗树,有
m
m
m次询问,每次询问有两个操作:
(
1
)
(1)
(1)将
[
a
,
b
]
[a,b]
[a,b]路径上的点依次加上
1
2
,
2
2
,
3
2
,
.
.
.
,
l
e
n
2
,
l
e
n
=
p
a
t
h
(
a
,
b
)
1^2,2^2,3^2,...,len^2,len=path(a,b)
12,22,32,...,len2,len=path(a,b)。
(
2
)
(2)
(2)询问
x
x
x点的值。
思路:
先考虑在线性的情况下如何实现两个操作。
不难发现,直接修改的瓶颈是不能确保每次修改的都一样,但是发现我们最终查询的时候只是单点查询,所以我们可以考虑将每个点的值作为变量,让后维护常量。
通过以上分析,我们可以考虑将操作
1
1
1转换成二次函数,比如当前要加区间
[
l
,
r
]
[l,r]
[l,r],那么就相当于加上一个
(
x
−
l
)
2
(x-l)^2
(x−l)2的二次函数,其中
x
∈
[
l
+
1
,
r
+
1
]
x\in [l+1,r+1]
x∈[l+1,r+1],将其展开
x
2
+
l
2
−
2
∗
x
∗
l
x^2+l^2-2*x*l
x2+l2−2∗x∗l,显然我们可以分别对三个系数单独维护,即
1
,
l
2
,
2
l
1,l^2,2l
1,l2,2l,也就是线段树区间修改的过程,之后查询的时候乘上对应的位置即可。
那么在树上怎么求呢?显然只需要一个树剖即可,树剖将其分成
l
o
g
n
logn
logn段区间每段区间都是连续的,所以注意一下细节直接写就好啦。
//#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
//#pragma GCC optimize(2)
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#include<random>
#include<cassert>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid ((tr[u].l+tr[u].r)>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std;
//void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); }
//void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); }
//void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); }
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
const int N=1000010,mod=1e9+7,INF=0x3f3f3f3f;
const double eps=1e-6;
int n;
vector<int>v[N];
int fa[N],depth[N],se[N],son[N],dfn[N],tot,top[N];
struct Seg {
struct Node {
int l,r;
LL sum,lazy;
}tr[N<<2];
void pushup(int u) {
tr[u].sum=tr[L].sum+tr[R].sum;
}
void pushdown(int u) {
LL lazy=tr[u].lazy; tr[u].lazy=0;
tr[L].sum+=lazy*Len(L); tr[L].lazy+=lazy;
tr[R].sum+=lazy*Len(R); tr[R].lazy+=lazy;
}
void build(int u,int l,int r) {
tr[u]={l,r};
if(l==r) return;
build(L,l,Mid); build(R,Mid+1,r);
}
void change(int u,int l,int r,LL sum) {
if(tr[u].l>=l&&tr[u].r<=r) {
tr[u].sum+=Len(u)*sum;
tr[u].lazy+=sum;
return ;
}
pushdown(u);
if(l<=Mid) change(L,l,r,sum);
if(r>Mid) change(R,l,r,sum);
// pushup(u);
}
LL query(int u,int pos) {
if(tr[u].l==tr[u].r) return tr[u].sum;
pushdown(u);
if(pos<=Mid) return query(L,pos);
else return query(R,pos);
// pushup(u);
}
}t1,t2,t3;
void dfs1(int u,int f) {
depth[u]=depth[f]+1; fa[u]=f;
se[u]=1;
for(auto x:v[u]) {
if(x==f) continue;
dfs1(x,u);
se[u]+=se[x];
if(se[x]>se[son[u]]) son[u]=x;
}
}
void dfs2(int u,int t) {
top[u]=t; dfn[u]=++tot;
if(son[u]) dfs2(son[u],t);
for(auto x:v[u]) {
if(x==son[u]||x==fa[u]) continue;
dfs2(x,x);
}
}
void change(int x,int y,int cnt) {
int l=1,r=cnt;
while(top[x]!=top[y]) {
if(depth[top[x]]>depth[top[y]]) {
LL add=dfn[x]+l; l+=depth[x]-depth[top[x]]+1;
t1.change(1,dfn[top[x]],dfn[x],1);
t2.change(1,dfn[top[x]],dfn[x],add*add);
t3.change(1,dfn[top[x]],dfn[x],add);
x=fa[top[x]];
} else {
int now=depth[y]-depth[top[y]]+1;
LL add=dfn[top[y]]+(r-now-1); r-=now;
t1.change(1,dfn[top[y]],dfn[y],1);
t2.change(1,dfn[top[y]],dfn[y],add*add);
t3.change(1,dfn[top[y]],dfn[y],add);
y=fa[top[y]];
}
}
if(depth[x]>depth[y]) {
LL add=dfn[x]+l; l+=depth[x]-depth[y]+1;
t1.change(1,dfn[y],dfn[x],1);
t2.change(1,dfn[y],dfn[x],add*add);
t3.change(1,dfn[y],dfn[x],add);
} else {
int now=depth[y]-depth[x]+1;
LL add=dfn[x]-(r-now+1); r-=now;
t1.change(1,dfn[x],dfn[y],1);
t2.change(1,dfn[x],dfn[y],add*add);
t3.change(1,dfn[x],dfn[y],add);
}
}
int lca(int x,int y) {
while(top[x]!=top[y]) {
if(depth[top[x]]<depth[top[y]]) swap(x,y);
x=fa[top[x]];
}
if(depth[x]<depth[y]) return x;
else return y;
}
int main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);
scanf("%d",&n);
for(int i=1;i<=n-1;i++) {
int a,b; scanf("%d%d",&a,&b);
v[a].pb(b); v[b].pb(a);
}
dfs1(1,0); dfs2(1,1);
t1.build(1,1,n); t2.build(1,1,n); t3.build(1,1,n);
int m; scanf("%d",&m);
while(m--) {
int op,x,y;
scanf("%d%d",&op,&x);
if(op==1) {
scanf("%d",&y);
change(x,y,depth[x]+depth[y]-2*depth[lca(x,y)]+1);
} else {
//if(x==2) cout<<t3.query(1,dfn[x])<<"**"<<endl;
printf("%lld\n",t1.query(1,dfn[x])*dfn[x]*dfn[x]+t2.query(1,dfn[x])-2*dfn[x]*t3.query(1,dfn[x]));
}
}
return 0;
}
/*
*/