[hdu1512] Monkey King

题意:

有n个猴子,每个猴子有一个能力值,猴子之间喜欢打架,打完架之后就变成好朋友了,就不会再打架了,现给出m个关系(x,y),表示猴子x要和猴子y打架,打完架之后这两个猴子的能力值会减半,然后输出它们这个朋友圈里德最大能力值

题解:

左偏树+并查集

显然要用左偏树来维护每个并查集里猴子的能力值

这里猴子打完架之后能力值会减半,所以相当于要在左偏树中pop这个点,然后再merge

注意:并查集和左偏树是两个独立的数据结构,之间没有影响关系,并查集只是单纯地维护连通性,而对左偏树的结构不产生影响

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
#define N 100010
using namespace std;

int fa[N],rs[N],ls[N],v[N],dis[N];

int gi() {
  int x=0,o=1; char ch=getchar();
  while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
  if(ch=='-') o=-1,ch=getchar();
  while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
  return o*x;
}

int find(int x) {
  return x==fa[x]?x:fa[x]=find(fa[x]);
}

int merge(int x, int y) {
  if(!x) return y;
  if(!y) return x;
  if(v[x]<v[y]) swap(x,y);
  rs[x]=merge(rs[x],y);
  fa[rs[x]]=x;
  if(dis[rs[x]]>dis[ls[x]]) swap(rs[x],ls[x]);
  if(rs[x]==0) dis[x]=0;
  else dis[x]=dis[rs[x]]+1;
  return x; 
}

int pop(int x) {
  int l=ls[x],r=rs[x];
  fa[l]=l,fa[r]=r;
  ls[x]=rs[x]=dis[x]=0;
  return merge(l,r);
}

int main() {
  int n,m;
  while(~scanf("%d", &n)) {
    for(int i=1; i<=n; i++) {
      ls[i]=rs[i]=dis[i]=0;
      fa[i]=i;
      v[i]=gi();
    }
    m=gi();
    while(m--) {
      int x=gi(),y=gi(),p,q;
      x=find(x),y=find(y);
      if(x==y) {puts("-1");continue;}
      else {
	v[x]/=2;
	 p=pop(x),p=merge(p,x);
	v[y]/=2;
	q=pop(y),q=merge(q,y);
	printf("%d
", v[merge(p,q)]);
      }
    }
  }
  return 0;
}
原文地址:https://www.cnblogs.com/HLXZZ/p/7639274.html