题解:HDU 7435

Link

1. Description

给定一棵根为 \(1\) 的有根树,点 \(x\) 的点权为 \(A_x\),定义 \(S(u)\) 表示以 \(u\) 为根的子树对应的点集,\(g_{u,v}= \max(A_u,A_v)\times|A_u-A_v|\)\(f_i=\sum_{u\in S(i)}\sum_{v\in S(i)} g_{u,v}\),对于 \(1\le i\le n\),求出 \(f_i\)

2. Solution

首先一个很简单的分解 \(f_i=\sum_{u\in son_i} f_u+\sum_{u\in son_i}\sum_{v\in son_i}val(u,v)\),其中 \(val(u,v)\) 表示 \(\sum_{x\in S(u)}\sum_{y\in S(v)} g_{x,y}\),特殊的,\(val(u,u)=0\)

我们现在考虑怎么求出所有的 \(val(u,v)\),显然可以使用树上启发式合并求解,将重儿子对应的子树点集作为初始集合,依次枚举轻儿子,在 \(f_i\) 中加上轻儿子对应的子树点集与当前集合的贡献,然后将轻儿子对应的子树点集加入集合即可。

然后简单的推式子,将 \(g_{u,v}\) 的式子略微分类讨论一下有 \(g_{u,v}=\begin{cases}A_u^2-A_u\times A_v\ (A_u\ge A_v)\\A_v^2-A_u\times A_v\ (A_u<A_v)\end{cases}\),只需要使用权值树状数组分别维护当前集合的零次方和,一次方和,二次方和,就可以在 \(O(\log n)\) 的时间复杂度内求解出一个点对于一个点集的贡献。

最后时间复杂度为 \(O(n\log^2 n)\),足够通过此题了。

3. Code

/*by qwer6*/
/*略去缺省源和快读快写*/
const int N=5e5+5;
int n,cnt_dfn,tot;
ull ans;
int siz[N],son[N],dfn[N],L[N],R[N];
ull a[N],tmp[N],f[N];
struct Chain_forward_star{
	struct Edge{
		int v,nxt;
	}e[N<<1];
	int cnt_edge;
	int head[N];
	void AddEdge(int u,int v){
		e[++cnt_edge]={v,head[u]};
		head[u]=cnt_edge;
	}
}G;
struct Node{
	ull sum0,sum1,sum2;
	Node(ull _sum0=0,ull _sum1=0,ull _sum2=0){
		sum0=_sum0,sum1=_sum1,sum2=_sum2;
	}
	Node operator +(const Node &a)const{
		return {sum0+a.sum0,sum1+a.sum1,sum2+a.sum2};
	}
	Node operator -(const Node &a)const{
		return {sum0-a.sum0,sum1-a.sum1,sum2-a.sum2};
	}
	void print(){
		write(sum0),Spa,write(sum1),Spa,write(sum2),Nxt;
	}
};
struct Binary_tree{
	Node c[N];
	#define lowbit(x) (x&-x)
	void add(int x,Node v){
		for(int i=x;i<=tot;i+=lowbit(i))c[i]=c[i]+v;
	}
	void sub(int x,Node v){
		for(int i=x;i<=tot;i+=lowbit(i))c[i]=c[i]-v;
	}
	Node query(int x){
		Node res;
		for(int i=x;i;i-=lowbit(i))res=res+c[i];
		return res;
	}
	Node query(int l,int r){
		return query(r)-query(l-1);
	}
	#undef lowbit
}bit;
ull count(int x){
	ull res=0;
	if(x<tot){
		Node Ans=bit.query(x+1,tot);
		res+=Ans.sum2-tmp[x]*Ans.sum1;
	}
	if(x>1){
		Node Ans=bit.query(1,x-1);
		res+=Ans.sum0*tmp[x]*tmp[x]-tmp[x]*Ans.sum1;
	}
	return res;
}
void dfs(int u,int fa){
	siz[u]=1;
	L[u]=++cnt_dfn;
	dfn[cnt_dfn]=u;
	a[u]=lower_bound(tmp+1,tmp+tot+1,a[u])-tmp;
	for(int i=G.head[u],v;i;i=G.e[i].nxt){
		v=G.e[i].v;
		if(v==fa)continue;
		dfs(v,u);
		siz[u]+=siz[v];
		if(siz[son[u]]<siz[v])son[u]=v;
	}
	R[u]=cnt_dfn;
}
void redfs(int u,int fa,bool flag){
	for(int i=G.head[u],v;i;i=G.e[i].nxt){
		v=G.e[i].v;
		if(v==fa||v==son[u])continue;
		redfs(v,u,1);
		f[u]+=f[v];
	}
	if(son[u])redfs(son[u],u,0),f[u]+=f[son[u]];
	for(int i=G.head[u],v;i;i=G.e[i].nxt){
		v=G.e[i].v;
		if(v==fa||v==son[u])continue;
		for(int j=L[v];j<=R[v];j++)
			f[u]+=count(a[dfn[j]]);
		for(int j=L[v],x;j<=R[v];j++){
			x=a[dfn[j]];
			bit.add(x,Node(1,tmp[x],tmp[x]*tmp[x]));
		}
	}
	f[u]+=count(a[u]);
	bit.add(a[u],Node(1,tmp[a[u]],tmp[a[u]]*tmp[a[u]]));
	if(flag){
		for(int i=L[u],x;i<=R[u];i++){
			x=a[dfn[i]];
			bit.sub(x,Node(1,tmp[x],tmp[x]*tmp[x]));
		}
	}
	ans^=(f[u]*2);
}
signed main(){
	read(n);
	for(int i=2,u,v;i<=n;i++){
		read(u),read(v);
		G.AddEdge(u,v);
		G.AddEdge(v,u);
	}
	for(int i=1;i<=n;i++)tmp[i]=read(a[i]);
	sort(tmp+1,tmp+n+1);
	tot=unique(tmp+1,tmp+n+1)-tmp-1;
	dfs(1,0);
	redfs(1,0,0);
	write(ans);
}
posted @ 2025-04-17 16:12  陈牧九  阅读(14)  评论(0)    收藏  举报