题意:
要求我们维护子树的信息,将所求答案进行异或
思路:
首先我们需要前缀知识(树上启发式合并)。题目上的公式可以化为max* max-max*min。考虑将一个点加到当前集合中,我们可以利用树状数组来快速维护这个信息,同时还可以进行单点修改。考虑如何在树上进行这个操作,应该先计算轻子树,然后再计算重子树,然后将u和轻子树的信息与重子树进行合并。在计算过程中,我们始终要保留重子树的信息,合并完成后,要将轻子树的信息进行清空,因为本身就是一个迭代的过程,每一个轻子树都是相互独立的,相当于我们把轻子树的信息合并到重子树上去,整个过程使用一个树状数组,所以要清空。时间复杂度O(nlog²)
代码实现
// #pragma GCC optimize(3,"Ofast","inline")
// #pragma GCC optimize(2)
#include <bits/stdc++.h>
using namespace std;
#define all(v) v.begin(), v.end()
#define point(n) fixed << setprecision(n)
#define IOS \
ios::sync_with_stdio(false); \
cin.tie(0), cout.tie(0);
#define endl '\n'
#define inf 0x3f3f3f3f
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll> PII;
typedef pair<ll, array<ll, 2>> PIA;
const int N = 1e6 + 10,mod=1e9+7;
const ll INF = 0x3f3f3f3f3f3f3f3f;
int n, m, k;
int f[N];
vector<int >h[N];
int sz[N],son[N];
ull cnt;
template<class T>
struct BIT {
vector<T> c;
int size;
void init(int s) {
size = s;
c.resize(size + 1, 0);
}
T query(int x) { // 1 ... x
assert(x <= size);
T s = 0;
for (; x; x -= x & (-x)) {
s += c[x];
}
return s;
}
void modify(int x, T s) {
assert(x != 0);
for (; x <= size; x += x & (-x)) {
c[x] += s;
}
}
};
BIT<ull>w1,w2,w3;
ull ans[N];
void dfs_son(int u,int fa)
{
sz[u]=1;
for(auto g:h[u]){
if(g==fa)continue;
dfs_son(g,u);
if(sz[g]>sz[son[u]]){
son[u]=g;
}
sz[u]+=sz[g];
}
}
void get1(int u,int fa,int pson,ull sign)
{
// max*max-max*min 分两种情况,大于f[u]和小于等于f[u],直接利用题目的公式进行计算
cnt+=((w1.query(1e6)-w1.query(f[u])+w3.query(f[u])*f[u]*f[u])-w2.query(1e6)*f[u])*2;
w1.modify(f[u],sign*f[u]*f[u]);//维护平方和
w2.modify(f[u],sign*f[u]);//维护前缀和
w3.modify(f[u],sign);//维护个数
for(auto g:h[u]){
if(g==fa||g==pson)continue;
get1(g,u,pson,sign);
}
}
void dfs(int u,int fa,int op)
{
for(auto g:h[u]){
if(g==fa||g==son[u])continue;
dfs(g,u,0);
}
if(son[u])dfs(son[u],u,1);//求解重儿子信息
get1(u,fa,son[u],1);//计算贡献,将u和轻子树的信息与重子树进行合并
ans[u]=cnt;
if(!op)get1(u,fa,0,-1),cnt=0;//将当前子树的信息进行清空。
}
void solve()
{
cin >> n;
w1.init(1e6+10);
w2.init(1e6+10);
w3.init(1e6+10);
for(int i=1;i<n;i++){
int a,b;
cin >> a >> b;
h[a].push_back(b);
h[b].push_back(a);
}
for(int i=1;i<=n;i++){
cin >> f[i];
}
dfs_son(1,-1);//求重儿子
dfs(1,-1,1);
ull res=0;
for(int i=1;i<=n;i++){
res^=ans[i];
// cout<<ans[i]<<" \n"[i==n];
}
cout<<res<<endl;
}
int main()
{
IOS;
int _ = 1;
// cin >> _;
while (_--)
{
solve();
}
return 0;
}