- 点对的权值都是可以拆的
- 逆用完全平方公式,将两两乘积之和转化为和的平方
- 树上启发式合并的核心在于保留重儿子的信息
- 动态开点线段树空间计算:考虑到\(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
*/