• 点对的权值都是可以拆的
  • 逆用完全平方公式,将两两乘积之和转化为和的平方
  • 树上启发式合并的核心在于保留重儿子的信息
  • 动态开点线段树空间计算:考虑到\(2^{20}>10^6\),区间【1,1000000】至多分裂20次,产生21个子节点
  • 线段树合并:任意节点为空就不再递归
点击查看代码
#include <bits/stdc++.h>
using namespace std;
vector<int>a[500005];
long long w[500005],va[500005];
unsigned long long f[500005],sum[500005];
int dfn[500005],s[500005],cnt,h[500005];
int read1()
{
	char cc=getchar();
	while(!(cc>=48&&cc<=57))
	{
		if(cc=='-')
		{
			break;
		}
		cc=getchar();
	}
	bool f=false;
	int s=0;
	if(cc=='-')
	{
		f=true;
	}
	else
	{
		s=cc-48;
	}
	while(1)
	{
		cc=getchar();
		if(cc>=48&&cc<=57)
		{
			s=s*10+cc-48;
		}
		else
		{
			break;
		}
	}
	if(f==true)
	{
		s=-s;
	}
	return s;
}
struct t1
{
	int l,r,cnt;
	long long sum;
}t[500000*21+5];
int tot;
void add(int p,int l,int r,int x)
{
	if(l==r)
	{
		t[p].cnt++;
		t[p].sum+=(1ll*l*l);
		return;
	}
	int mid=(l+r)>>1;
	if(x<=mid)
	{
		if(!t[p].l)
		{
			t[p].l=++tot;
			t[tot].l=t[tot].r=t[tot].cnt=t[tot].sum=0;
		}
		add(t[p].l,l,mid,x);
	}
	else
	{
		if(!t[p].r)
		{
			t[p].r=++tot;
			t[tot].l=t[tot].r=t[tot].cnt=t[tot].sum=0;
		}
		add(t[p].r,mid+1,r,x);
	}
	t[p].cnt=t[t[p].l].cnt+t[t[p].r].cnt;
	t[p].sum=t[t[p].l].sum+t[t[p].r].sum;
}
int askcnt(int p,int l,int r,int u,int v)
{
	if(p==0)
	{
		return 0;
	}
	if(u<=l&&v>=r)
	{
		return t[p].cnt;
	}
	int mid=(l+r)>>1;
	int va=0;
	if(u<=mid)
	{
		va+=askcnt(t[p].l,l,mid,u,v);
	}
	if(v>mid)
	{
		va+=askcnt(t[p].r,mid+1,r,u,v);
	}
	return va;
}
long long asksum(int p,int l,int r,int u,int v)
{
	if(p==0)
	{
		return 0;
	}
	if(u<=l&&v>=r)
	{
		return t[p].sum;
	}
	int mid=(l+r)>>1;
	long long va=0;
	if(u<=mid)
	{
		va+=asksum(t[p].l,l,mid,u,v);
	}
	if(v>mid)
	{
		va+=asksum(t[p].r,mid+1,r,u,v);
	}
	return va;
}
void merge(int &p,int &q,int l,int r)
{
	if(!q)
	{
		return;
	}
	else if(!p)
	{
		p=q;
		return;
	}
	else
	{
		int mid=(l+r)>>1;
		merge(t[p].l,t[q].l,l,mid);
		merge(t[p].r,t[q].r,mid+1,r);
		if(l!=r)
		{
			t[p].cnt=t[t[p].l].cnt+t[t[p].r].cnt;
			t[p].sum=t[t[p].l].sum+t[t[p].r].sum;
		}
		else
		{
			t[p].cnt+=t[q].cnt;
			t[p].sum+=t[q].sum;
		}
	}
}
void dfs1(int n1,int fa)
{
	s[n1]=1;
	sum[n1]=w[n1];
	for(int i=0;i<a[n1].size();i++)
	{
		if(a[n1][i]!=fa)
		{
			dfs1(a[n1][i],n1);
			s[n1]+=s[a[n1][i]];
			sum[n1]+=sum[a[n1][i]];
			if(s[a[n1][i]]>s[h[n1]])
			{
				h[n1]=a[n1][i];
			}
		}
	}
}
void dfs2(int n1,int fa)
{
	dfn[n1]=++cnt;
	va[cnt]=w[n1];
	f[n1]=w[n1]*w[n1];
	int la=cnt;
	if(h[n1]!=0)
	{
		dfs2(h[n1],n1);
		f[n1]+=f[h[n1]];
		f[n1]+=(2*askcnt(h[n1],1,1000000,1,w[n1])*w[n1]*w[n1]);
		f[n1]+=(2*(t[h[n1]].sum-asksum(h[n1],1,1000000,1,w[n1])));
		merge(h[n1],n1,1,1000000);
		t[n1]=t[h[n1]];
		la=la+s[h[n1]]; 
	} 
	for(int i=0;i<a[n1].size();i++)
	{
		if(a[n1][i]!=fa&&a[n1][i]!=h[n1])
		{
			dfs2(a[n1][i],n1);
			f[n1]+=f[a[n1][i]];
			for(int k=la+1;k<=la+s[a[n1][i]];k++)
			{
				f[n1]+=(2*askcnt(n1,1,1000000,1,va[k])*va[k]*va[k]);
				f[n1]+=(2*(t[n1].sum-asksum(n1,1,1000000,1,va[k])));
			}
			merge(n1,a[n1][i],1,1000000);
			la=la+s[a[n1][i]];
		}
	}
}
int main()
{
	int n;
	cin>>n;
	for(int i=1;i<n;i++)
	{
		int u,v;
		u=read1();
		v=read1();
		a[u].push_back(v);
		a[v].push_back(u);
	}
	tot=n;
	t[0].l=t[0].r=t[0].cnt=t[0].sum=0;
	for(int i=1;i<=n;i++)
	{
		w[i]=read1();
		t[i].l=t[i].r=0;
		t[i].cnt=t[i].sum=0;
		add(i,1,1000000,w[i]);
	}
	dfs1(1,0);
	dfs2(1,0);
	unsigned long long ans=0;
	for(int i=1;i<=n;i++)
	{
		ans^=(f[i]-sum[i]*sum[i]);
	}
	cout<<ans<<endl;
	return 0;
}
//5832437305958 3 493000
/*
4
1 2
2 3
3 4
226279 15546 779906 971875
*/
posted @ 2024-07-22 23:04  D06  阅读(2)  评论(0编辑  收藏  举报