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]; } }到這本題就差很少結束了
別忘了一個分支內的任意節點不能相互影響,因此須要先對一個分支統計完貢獻後,再添加它的信息
#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; }