ccpc2020長春站F題 Strange Memory

dsu on treeios

題目連接

點我跳轉c++

題目大意

給定一棵包含 \(n\) 個節點的樹,每一個節點有個權值 \(a_i\)spa

\(∑_{i=1}^n∑_{j=i+1}^n[a_i⊕a_j=a_{lca(i,j)}](i⊕j).\)code

解題思路

題目保證了 \(a_i ≠ 0\) ,因此不存在 \(a_u⊕a_v = a_u\),即知足條件的\(a_u ⊕ a_v = a_{lca(u,v)}\)\(u , v\) 必定在不一樣分支ci

這點極大的簡單化了本問題get

因而在以 \(rt\) 爲根的子樹中,對於節點 \(u\) ,知足條件的點的異或值爲 \(a_u ⊕ a_{rt}\)it

\(u\) 對答案產生的貢獻只和 \(u\) 在二進制下每一位的數值有關係io

因而咱們能夠定義 \(f_{ijk}\) 表示異或值爲 \(i\) 的數 , 它們在二進制下第 \(j\) 位爲 \(k\) 的個數class

那麼對於 \(u\) , 它的貢獻能夠這麼算二進制

int x = a[u] ^ a[rt];
if(x <= 1000000) // a[i] <= 1e6
{
	for(int i = 17 ; i >= 0 ; i --)
	{
		int k = u >> i & 1;
		ans += (1LL << i) * f[x][i][k ^ 1]; 
	}
}

到這本題就差很少結束了

別忘了一個分支內的任意節點不能相互影響,因此須要先對一個分支統計完貢獻後,再添加它的信息

AC_Code

#include<bits/stdc++.h>
#define rep(i , a , b) for(int i = a ; i <= b ; i ++)
#define per(i , b , a) for(int i = b ; i >= a ; i --)
#define ll long long
#define pb push_back
#define fi first
#define se second
using namespace std; 
const int N = 1e5 + 10 , M = 1e6 + 10;
struct Edge{
	int nex , to;
}edge[N << 2];
int head[N] , TOT;
void add_edge(int u , int v)
{
	edge[++ TOT].nex = head[u];
	edge[TOT].to = v;
	head[u] = TOT;
}
int dep[N] , sz[N] , hson[N] , HH;
int a[N] , f[M][20][2];
ll ans;
void dfs(int u , int far)
{
	sz[u] = 1;
	dep[u] = dep[far] + 1;
	for(int i = head[u] ; i ; i = edge[i].nex)
	{
		int v = edge[i].to;
		if(v == far) continue ;
		dfs(v , u);
		sz[u] += sz[v];
		if(sz[v] > sz[hson[u]]) hson[u] = v;
	}
}
void change(int u , int far , int val)
{
	for(int i = 17 ; i >= 0 ; i --) f[a[u]][i][u >> i & 1] += val;
	for(int i = head[u] ; i ; i = edge[i].nex)
	{
		int v = edge[i].to;
		if(v == far || v == HH) continue ;
		change(v , u , val); 
	}
} 
void calc(int u , int far , int rt)
{
	int x = a[u] ^ a[rt];
	if(x <= 1000000)
	{
		for(int i = 17 ; i >= 0 ; i --)
		{
			int k = u >> i & 1;
			ans += (1LL << i) * f[x][i][k ^ 1]; 
		}
	}
	for(int i = head[u] ; i ; i = edge[i].nex)
	{
		int v = edge[i].to;
		if(v == far || v == HH) continue ;
		calc(v , u , rt);
	}
}
void dsu(int u , int far , int op)
{
	for(int i = head[u] ; i ; i = edge[i].nex)
	{
		int v = edge[i].to;
		if(v == far || v == hson[u]) continue ;
		dsu(v , u , 0);
	}
	if(hson[u]) dsu(hson[u] , u , 1) , HH = hson[u];
	for(int i = head[u] ; i ; i = edge[i].nex)
	{
		int v = edge[i].to ;
		if(v == far || v == HH) continue ;
		calc(v , u , u) , change(v , u , 1);	
	} 
	HH = 0;
	for(int i = 17 ; i >= 0 ; i --) f[a[u]][i][(u >> i) & 1] ++ ;
	if(!op) change(u , far , -1);	
}
signed main()
{
	ios::sync_with_stdio(false);
	int n ;
	cin >> n;
	rep(i , 1 , n) cin >> a[i];
	rep(i , 2 , n)
	{
		int u , v;
		cin >> u >> v;
		add_edge(u , v) , add_edge(v , u);	
	} 
	dfs(1 , 0);
	dsu(1 , 0 , 0);
	cout << ans << '\n';
	return 0;
}
相關文章
相關標籤/搜索