2020CCPC長春F. Strange Memory
阿新 • • 發佈:2022-03-05
題目大意
一棵以 \(1\) 為根的 \(n(2\leq n\leq 10^5)\) 的樹,每個節點 \(i\) 有權值 \(a_{i}(1\leq a_{i}\leq 10^6)\) ,求 \(\sum_{i=1}^{n}\sum_{j=i+1}^{n}[a_{i}\oplus a_{j}=a_{lca(i,j)}](i\oplus j)\) 。
思路
考慮 \(dsu\space on\space tree\) ,因為 \(a_{i}>0\) ,所以能夠產生貢獻的節點 \((i,j)\) 一定分屬 \(lca(i,j)\) 兩側,於是計算各個子樹的貢獻時,考慮到對於每個節點 \(x\) ,對其中一棵子樹中的節點 \(i\)
程式碼
#include<bits/stdc++.h> #include<unordered_map> #include<unordered_set> using namespace std; typedef long long LL; typedef unsigned long long ULL; typedef pair<int, int> PII; #define all(x) x.begin(),x.end() //#define int LL //#define lc p*2+1 //#define rc p*2+2 #define endl '\n' #define inf 0x3f3f3f3f #define INF 0x3f3f3f3f3f3f3f3f #pragma warning(disable : 4996) #define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0) const double eps = 1e-8; const LL MOD = 1000000007; const LL mod = 998244353; const int maxn = 100010; int N, A[maxn]; vector<int>G[maxn]; int vsize[maxn], hson[maxn], L[maxn], R[maxn], rnk[maxn], tot = 0; LL tmp; int f[1 << 20][20][2]; void add_edge(int from, int to) { G[from].push_back(to); G[to].push_back(from); } void add(int v, int t) { for (int i = 19; i >= 0; i--) f[A[v]][i][(v >> i) & 1] += t; } void dfs(int v,int p) { hson[v] = 0; L[v] = ++tot; rnk[tot] = v; vsize[v] = 1; for (int i = 0; i < G[v].size(); i++) { int to = G[v][i]; if (to == p) continue; dfs(to, v); vsize[v] += vsize[to]; if (!hson[v] || vsize[to] > vsize[hson[v]]) hson[v] = to; } R[v] = tot; } void dsu(int v, int p) { for (int i = 0; i < G[v].size(); i++) { int to = G[v][i]; if (to == p || to == hson[v]) continue; dsu(to, v);//單個子樹內的貢獻 for (int j = L[to]; j <= R[to]; j++) add(rnk[j], -1);//清空計數資訊 } if (hson[v]) dsu(hson[v], v); for (int i = 0; i < G[v].size(); i++) { int to = G[v][i]; if (to == p || to == hson[v]) continue; for (int j = L[to]; j <= R[to]; j++) { int tar = A[rnk[j]] ^ A[v]; for (int i = 19; i >= 0; i--) tmp += (1LL << i) * (LL)f[tar][i][((rnk[j] >> i) & 1) ^ 1]; } for (int j = L[to]; j <= R[to]; j++) add(rnk[j], 1); } add(v, 1);//加上自己的計數資訊 } void solve() { dfs(1, 0), dsu(1, 0); cout << tmp << endl; } int main() { IOS; cin >> N; for (int i = 1; i <= N; i++) cin >> A[i]; int u, v; for (int i = 1; i < N; i++) { cin >> u >> v; add_edge(u, v); } solve(); return 0; }