链接:https://ac.nowcoder.com/acm/contest/10167/C
来源:牛客网
题目描述
牛牛有一棵n个节点的树,每个节点都有一个价值p[i],对于某一条路径,定义路径的价值为路径上所有点的价值在二进制下按位与的值。现在,牛牛想知道所有树上路径的价值和为多少,你可以帮帮他吗?
注意,单独的一个点也算一条路径。
示例1
输入
复制
4,[0,1,2],[1,2,3],[1,2,2,1]
返回值
复制
8
说明
共有5条路径对答案有贡献,(1->2)贡献为2,(0)贡献为1,(1)贡献为2,(2)贡献为2,(3)贡献为1,所以答案为2+1+2+2+1=8。
备注:
1≤n≤1e5,0≤p[i]≤2^20 ,0≤u[i],v[i]<n
**思路:*我们可以枚举每一位,通过每一位的连通集合大小能够快速求出枚举的当前位在这个集合中所有路径上的贡献【集合大小为n的话其路径数为n(n+1)/2】。
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* @param n int整型 点的个数
* @param u int整型一维数组 每条边的起点
* @param v int整型一维数组 每条边的终点
* @param p int整型一维数组 每个点的价值
* @return long长整型
*/
private int[] f,size;
public long solve (int n, int[] u, int[] v, int[] p) {
// write code here
long ans=0;
f=new int[n];
size=new int[n];
for(int i=0;i<n;i++)
f[i]=i;
for(int x=0;x<20;x++){
Arrays.fill(size,0);
for(int i=0;i<n;i++)
f[i]=i;
for(int i=0;i<n-1;i++){
if((p[u[i]]>>x&1)!=0 && (p[v[i]]>>x&1)!=0)
f[find(u[i])]=find(v[i]);
}
for(int i=0;i<n;i++)
size[find(i)]++;
for(int i=0;i<n;i++){
if((p[i]>>x&1)!=0)
ans+=size[i]*(size[i]+1L)/2<<x;
}
}
return ans;
}
private int find(int x){
if(f[x]==x)
return x;
return f[x]=find(f[x]);
}
}