nowcoder911J 异或的路径
程序员文章站
2022-06-28 11:51:12
题目链接 题意 给出一棵树,每条边有边权。求$\sum\limits_{i=1}^n{f(i,j)}$,$f(i,j)$表示从i到j路径的异或和。 思路 $g_i$表示从根到$i$的异或和,两点之间的路径异或和就可以用$g_i \otimes g_j$表示。 先然$g_i$可以一次$dfs$求出来。 ......
题意
给出一棵树,每条边有边权。求\(\sum\limits_{i=1}^n{f(i,j)}\),\(f(i,j)\)表示从i到j路径的异或和。
思路
\(g_i\)表示从根到\(i\)的异或和,两点之间的路径异或和就可以用\(g_i \otimes g_j\)表示。
先然\(g_i\)可以一次\(dfs\)求出来。然后就是统计答案。按位考虑,每一位的数量是当前位置为0的个数与1的个数的成绩,再乘以当前位置的贡献即可。
代码
/* * @author: wxyww * @date: 2019-06-05 07:59:07 * @last modified time: 2019-06-05 08:30:46 */ #include<cstdio> #include<iostream> #include<cstdlib> #include<cstring> #include<algorithm> #include<queue> #include<vector> #include<ctime> using namespace std; typedef long long ll; const int n = 100000 + 100,mod = 1000000007; ll read() { ll x=0,f=1;char c=getchar(); while(c<'0'||c>'9') { if(c=='-') f=-1; c=getchar(); } while(c>='0'&&c<='9') { x=x*10+c-'0'; c=getchar(); } return x*f; } int f[2][100],b[n]; struct node { int u,v,w,nxt; }e[n]; int ejs,head[n]; void add(int u,int v,int w) { e[++ejs].v = v;e[ejs].nxt = head[u];head[u] = ejs;e[ejs].w = w; } void dfs(int u) { for(int i = head[u];i;i = e[i].nxt) { int v = e[i].v; b[v] = b[u] ^ e[i].w; dfs(v); } } void solve(int x) { for(int i = 0;i <= 20;++i) f[(x >> i) & 1][i]++; } int main() { int n = read(); for(int i = 2;i <= n;++i) { int u = read(),w = read(); add(u,i,w); } dfs(1); ll ans = 0; for(int i = 1;i <= n;++i) solve(b[i]); for(int i = 0;i <= 20;++i) ans += 1ll * f[0][i] * f[1][i] % mod * (1 << i) % mod,ans %= mod; cout<<ans * 2 % mod; return 0; }
上一篇: 如何防御与删除calc.exe病毒