题意
题解
与运算同时出现在底数与指数,难以处理和式。
∑ 1 ≤ u ≤ v ≤ n f ( u , v ) f ( u , v ) \sum_{1\leq u\leq v\leq n}f(u,v)^{f(u,v)} 1≤u≤v≤n∑f(u,v)f(u,v) 考虑直接求解 f ( u , v ) f(u,v) f(u,v) 后求和。限制 N D ≤ 3 × 1 0 6 ND\leq3\times 10^6 ND≤3×106 指出,当点数很大时,树上与子节点连边数大于 1 1 1 的节点数很少。先考虑链上的情况,根据与运算的性质,当 u u u 不变时, f ( u , v ) f(u,v) f(u,v) 的取值只有 O ( log A u ) O(\log A_u) O(logAu) 种可能,取值的变化仅发生在 A u A_u Au 的二进制表示中为 1 1 1 的位变为 0 0 0 的情况下。同理,对于以 u u u 为根的子树,对任一子树中的节点 v v v,有 f ( u , v ) f(u,v) f(u,v) 取值只有 O ( log A u ) O(\log A_u) O(logAu) 种可能性,那么可以进行哈希。
设 M = ⌊ log 2 A ⌋ + 1 M=\lfloor\log_2A\rfloor+1 M=⌊log2A⌋+1。基于 s t d : : m a p std::map std::map 的树上哈希递推,时间复杂度 O ( N M log M ) O(NM\log M) O(NMlogM)。任一对节点 ( u , v ) (u,v) (u,v) 的 f ( u , v ) f(u,v) f(u,v),仅在 l c a ( u , v ) lca(u,v) lca(u,v) 处统计一次,时间复杂度为 O ( min ( D 2 M 2 , N 2 ) ) O(\min(D^2M^2,N^2)) O(min(D2M2,N2))。
min ( D 2 M 2 , N 2 ) ≤ D 2 M 2 + N 2 ≤ 2 N M D \min(D^2M^2,N^2)\leq D^2M^2+N^2\leq 2NMD min(D2M2,N2)≤D2M2+N2≤2NMD 那么总时间复杂度为 O ( N M ( D + log M ) ) O(NM(D+\log M)) O(NM(D+logM)),暴力求解即可。
#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = l, _ = r; i < _; ++i)
#define ft first
#define sd second
typedef long long ll;
const int maxn = 200005, _p = 786433, _g = 10;
int N, Res, A[maxn], ind[_p], gPw[_p];
vector<int> G[maxn];
map<int, int> mp[maxn];
void add(int x, int d)
{
if (x % _p == 0)
return;
int y = gPw[(ll)ind[x % _p] * x % (_p - 1)];
Res = (Res + (ll)y * d % _p) % _p;
}
void dfs(int u, int p)
{
add(A[u], 1);
++mp[u][A[u]];
for (auto &v : G[u])
if (v != p)
{
dfs(v, u);
for (auto &x : mp[v])
for (auto &y : mp[u])
add(x.ft & y.ft, (ll)x.sd * y.sd % _p);
for (auto &x : mp[v])
mp[u][x.ft & A[u]] += x.sd;
mp[v].clear();
}
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
for (int i = 0, x = 1; i < _p - 1; ++i)
ind[x] = i, gPw[i] = x, x = (ll)x * _g % _p;
cin >> N;
rep(i, 0, N) cin >> A[i];
rep(i, 1, N)
{
int u, v;
cin >> u >> v;
--u, --v;
G[u].push_back(v), G[v].push_back(u);
}
dfs(0, -1);
cout << Res << '\n';
return 0;
}