Monkey King(可并堆)

Posted sto324

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Monkey King(可并堆)相关的知识,希望对你有一定的参考价值。

题意

有n只猴子,一开始互不认识,每次有两只猴子要打架,他们会找来自己认识的最厉害的猴子来帮他们打(然而他们就看戏),打完后打架的猴子(不是看戏的)武力值会减少一半(下取整),并且他们也互相认识了,在这时询问他们认识的猴子中最厉害的猴子的武力值,打架的在之前认识输出-1。

n,m<=100000

题解

直接用可并堆就好了,对于打完认识就是合并两个队伍,但是对于武力值减少怎么弄?

就直接把老大踢出去,再重新来过。具体实现就是把老大的ls,rs合并,这样他就出来了,然后再合并他和ls(rs)的堆。

具体实现的时候有一些细节,在代码里面实现。

技术图片
#include<bits/stdc++.h>
using namespace std;

const int maxn=100005;
int n,m,a[maxn];
int fa[maxn],ls[maxn],rs[maxn],dis[maxn],val[maxn];

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


int merge(int A,int B)
  if(!A) return B;
  if(!B) return A;
  if(val[A]<val[B]) swap(A,B);
  rs[A]=merge(rs[A],B);
  fa[rs[A]]=A;
  if(dis[rs[A]]>dis[ls[A]]) swap(rs[A],ls[A]);
  if(!rs[A]) dis[A]=0;
  else dis[A]=dis[rs[A]]+1;
  return A;


int pop(int x)//int 是因为不改变ls,rs的话合并x可能他是叶子节点,就会RE
  fa[ls[x]]=ls[x];
  fa[rs[x]]=rs[x];
  fa[x]=x;
  int ret=merge(ls[x],rs[x]);
  ls[x]=rs[x]=0;//求出上面才能改
  return ret;


int main()
  //freopen("testdata.in","r",stdin);
  while(scanf("%d",&n)!=EOF)
    for(int i=1;i<=n;i++)
      scanf("%d",&val[i]);
      fa[i]=i;
      ls[i]=rs[i]=dis[i]=0;
    
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
      int x,y;
      scanf("%d%d",&x,&y);
      int dx=find(x),dy=find(y);
      if(dx==dy)printf("-1\n");continue;
      //printf("*--------%d %d------------*\n",dx,dy);
      int xx=pop(dx),yy=pop(dy);
      //printf("*---------%d %d------*\n",xx,yy);
      val[dx]>>=1;
      val[dy]>>=1;
      merge(dx,find(xx));
      merge(dy,find(yy));
      merge(find(dx),find(dy));
      //for(int j=1;j<=n;j++) printf("%d ",fa[j]);
      //putchar(10);
      printf("%d\n",val[find(dx)]);
    
  
  return 0;
View Code

 

以上是关于Monkey King(可并堆)的主要内容,如果未能解决你的问题,请参考以下文章

可并堆

bzoj3011 可并堆

可并堆

[BZOJ 2333] 棘手的操作 可并堆

BZOJ3252: 攻略 可并堆

左偏树(可并堆)