牛客编程巅峰赛S2第10场 - 钻石&王者 做题记录
时隔半个月。。。终于搞懂C题了。。
先上原来写的超时代码 ,卡在90%。
写了一个暴力dfs , 应该是O(N^2)的
主要是没有用到与运算的性质,没有按位与。 简单粗暴的与运算导致重复走了很多个点。
long res =0;
public long solve (int n, int[] u, int[] v, int[] p) {
Map> book = new HashMap();
for(int i=0;i<n;++i){
book.put(i,new ArrayList());
}
for(int i=0;i<u.length;++i){
int start = u[i];
int end =v[i];
book.get(start).add(end);
book.get(end).add(start);
}
for(int i=0;i<n;++i){
//以点i为起点
long cur =-1;
boolean[] flag = new boolean[n];
fun(book,p,cur,flag,i);
}
long r= 0;
for(int pp:p){
r+= pp;
}
return (res -r)/2+r;
}
public void fun(Map> book,int[] p,long cur,boolean[] flag,int i){
if(flag[i] || cur ==0){
return;
}
if(cur ==-1){
//起点
cur = p[i];
}else{
cur = cur & p[i];
}
res += cur;
flag[i]=true;
List next = book.get(i);
for(int n : next){
fun(book,p,cur,flag,n);
}
} 按照与运算+连通块的性质, 写bfs
(按位与 : 例如 15 = 8+4+2+1 , 即 fun(15) = fun(1<<3) + fun(1<<2) + fun(1<<1) + fun(1<<0) )
public long solve (int n, int[] u, int[] v, int[] p) {
long res =0;
List<Integer>[] edges = new ArrayList[n];
for(int i=0;i<edges.length;++i){
edges[i] = new ArrayList<>();
}
for(int i=0;i<u.length;++i){
edges[u[i]].add(v[i]);
edges[v[i]].add(u[i]);
}
int base =1;
for(int i=0;i<20;++i){
//求当前base的连通块数量
boolean[] vis = new boolean[n];
for(int j=0;j<n;++j){
int cnt = bfs(edges,p,j,base,vis);
res += ((long)cnt*(cnt+1))/2*base;
}
base = base <<1;
}
return res;
}
public int bfs(List<Integer>[] edges,int[] p ,int cur,int base,boolean[] vis){
if(vis[cur] || (p[cur]&base) ==0){
return 0;
}
int res =0;
Deque<Integer> queue = new LinkedList<>();
queue.offerLast(cur);
while(!queue.isEmpty()){
cur = queue.pollFirst();
res ++;
vis[cur] = true;
for(int edge : edges[cur]){
if((p[edge]&base)!=0 && !vis[edge]){
queue.offerLast(edge);
}
}
}
return res;
}
连通块问题也可以使用并查集:
public long solve (int n, int[] u, int[] v, int[] p) {
long res =0;
//按位与,20位
int base =1;
for(int cnt =0;cnt<20;++cnt){
//初始化并查集
int[] size = new int[n];
Arrays.fill(size,0);
int[] f=new int[n];
for(int i=0;i<n;++i){
f[i] = i;
}
for(int i=0;i<u.length;++i){
if( (p[u[i]]&base)!=0 && (p[v[i]]&base)!=0 ){
//并u[i] v[i]
f[find(f,u[i])] = find(f,v[i]);
}
}
for(int i=0;i<n;++i){
size[find(f,i)]++;
}
ArrayTools.printArray(size);
for(int i=0;i<n;++i){
if((p[i]&base) !=0){
res += (long)size[i]*(size[i]+1)/2*base;
}
}
base =base <<1;
}
return res;
}
public int find(int[] f,int x){
if(f[x] ==x){
return x;
}
f[x]=find(f,f[x]);
return f[x];
} 
