题意
给一颗\(n\)个点的树,共有\(q\)次以下类型的操作
1 x y
:将从\(x\)到\(y\)这条链上的第\(k\)个点的值加上\(k^2\)
2 x
:询问\(x\)点的值
\(1\le n,q\le 10^5\)
题解
首先重链剖分将树剖分为\(\log n\)条不相交的链,由于同一条链上点的\(dfn\)是连续的,所以我们可以维护每一条链上以\(dfn\)为自变量的二次函数的和。对于某一条重链,其\(dfn\)最小为\(dfnl\),最大为\(dfnr\),假设某次1操作覆盖到了它,则相当于在\([dfnl,dfnr]\)这个区间上添加了一段二次函数(以\(dfn\)为自变量)。每次2操作相当于查询x所在的链上所有二次函数在\(dfn[x]\)处的值的和。由于加上的二次函数可以表示为\((x-h)^2=x^2-2hx+h^2\),所以我们维护\(x^2,x,1\)前的系数即可。
具体地,对于每次1操作:
\(x\rightarrow lca\)方向上:对于一条重链上点\(nx\)到点\(ny(dep_{nx}<dep_{ny}即id_{nx}<id_{ny})\)的一段,则相当于在\([id_{nx},id_{ny}]\)这个连续区间上添加了一个二次函数\((X-(dis(x,nx)+1+id_{nx}))^2\)
\(lca\rightarrow y\)方向上:对于一条重链上点\(nx\)到点\(ny(dep_{nx}<dep_{ny}即id_{nx}<id_{ny})\)的一段,则相当于在\([id_{nx},id_{ny}]\)这个连续区间上添加了一个二次函数\((X-(id_{nx}-(dis(nx,x)+1))^2\)
#include <bits/stdc++.h>
#define ls o<<1
#define rs o<<1|1
#define mid ((l+r)>>1)
using namespace std;
using ll=long long ;
const int N=100005;
struct edge{
int nt,v;
}e[N<<1];
int h[N],cnt=0,a[N];
inline void add(int u,int v){
e[++cnt].v=v;e[cnt].nt=h[u];h[u]=cnt;
}
ll s[3][N<<2],addv[3][N<<2];
int x,y,op,z,n,m,r,p,ov[N];
void pushdown(int k,int o,int l,int r){
if(l==r)return ;
if(addv[k][o]!=0){
s[k][ls]+=(mid-l+1)*addv[k][o];
s[k][rs]+=(r-mid)*addv[k][o];
addv[k][ls]+=addv[k][o];
addv[k][rs]+=addv[k][o];
addv[k][o]=0;
}
}
void pd(int o,int l,int r){
pushdown(0,o,l,r);
pushdown(1,o,l,r);
pushdown(2,o,l,r);
}
inline void mt(int o){
s[0][o]=s[0][ls]+s[0][rs];
s[1][o]=s[1][ls]+s[1][rs];
s[2][o]=s[2][ls]+s[2][rs];
}
void upd(int o,int l,int r,int x,int y,ll d){
if(x<=l&&r<=y){
ll na=r-l+1;
++addv[0][o];s[0][o]+=na;
addv[1][o]-=2ll*d;s[1][o]-=2ll*na*d;
addv[2][o]+=d*d;s[2][o]+=1ll*d*d*na;
}
else{
pd(o,l,r);
if(x<=mid){upd(ls,l,mid,x,y,d);}
if(y>mid){upd(rs,mid+1,r,x,y,d);}
mt(o);
}
}
ll query(int o,int l,int r,int x){
if(l==r){return s[0][o]*x*x+s[1][o]*x+s[2][o];}
else{
pd(o,l,r);
if(x<=mid){return query(ls,l,mid,x);}
else return query(rs,mid+1,r,x);
}
}
int na,dep[N],fa[N],son[N],sz[N],id[N],top[N],tot=0;
void dfs1(int u){
na=-1;
for(int i=h[u];i;i=e[i].nt){
int v=e[i].v;if(v==fa[u])continue;
fa[v]=u;sz[v]=1;dep[v]=dep[u]+1;
dfs1(v);
sz[u]+=sz[v];
if(na<sz[v]){na=sz[v];son[u]=v;}
}
}
void dfs2(int u,int ntop){
id[u]=++tot;top[u]=ntop;
if(!son[u])return ;
dfs2(son[u],ntop);
for(int i=h[u];i;i=e[i].nt){
int v=e[i].v;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);
x=fa[top[x]];
}
return dep[x]<dep[y]?x:y;
}
void chain_add(int x,int y){
int lc=lca(x,y);
int na=dep[x],nb=na-dep[lc];
while(top[x]!=top[y]){
if(dep[top[x]]>dep[top[y]]){
upd(1,1,n,id[top[x]],id[x],na-dep[top[x]]+1+id[top[x]]);
x=fa[top[x]];
}
else{
upd(1,1,n,id[top[y]],id[y],id[top[y]]-(dep[top[y]]-dep[lc]+nb+1));
y=fa[top[y]];
}
}
if(dep[x]<dep[y]){
upd(1,1,n,id[x],id[y],id[x]-(dep[x]-dep[lc]+nb+1));
}
else{
upd(1,1,n,id[y],id[x],na-dep[y]+1+id[y]);
}
}
void rt(int u){
dep[u]=1;sz[u]=1;tot=0;
dfs1(u);
dfs2(u,u);
}
void f1(){
int Q;
scanf("%d",&n);
for(int i=1;i<n;i++){
int x,y;scanf("%d%d",&x,&y);
add(x,y);add(y,x);
}
rt(1);
scanf("%d",&Q);
while(Q--){
int op;scanf("%d",&op);
if(op==1){
int x,y;scanf("%d%d",&x,&y);
chain_add(x,y);
}
else{
int x;scanf("%d",&x);
printf("%lld\n",query(1,1,n,id[x]));
}
}
}
int main(){
//freopen("6962.in","r",stdin);
f1();
return 0;
}