【题解】2021HDU多校第二场 HDU6962 I love tree

2021HDU多校第二场I love tree

题意

给一颗(n)个点的树,共有(q)次以下类型的操作

1 x y:将从(x)(y)这条链上的第(k)个点的值加上(k^2)

2 x:询问(x)点的值

(1le n,qle 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 ightarrow lca)方向上:对于一条重链上点(nx)到点(ny(dep_{nx}<dep_{ny}即id_{nx}<id_{ny}))的一段,则相当于在([id_{nx},id_{ny}])这个连续区间上添加了一个二次函数((X-(dis(x,nx)+1+id_{nx}))^2)

(lca ightarrow 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
",query(1,1,n,id[x]));
		}
	}
}
int main(){
	//freopen("6962.in","r",stdin);
	f1();
	return 0;
}
原文地址:https://www.cnblogs.com/bobh/p/15053034.html