题意:
猴子们打架 认识的猴子不会打架 两仅仅猴子打完以后就认识了 A认识B B认识C A也认识C 每次打架由两伙猴子进行 分别选出自己的最高战斗力 在战斗之后两仅仅猴子战斗力减半 给出m次打架 输出打架后这一伙猴子里的最强战斗力
思路:
推断两仅仅猴子是不是一伙的 用到并查集
高速找出一伙猴子中的最强战斗力用到堆 但打完架两伙猴子合并时堆须要nlogn复杂度 因此用左偏树取代堆
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 100010 int n,m,tot; int fa[N]; struct node { int v,l,r,dis; }nd[N]; int getf(int x) { if(x!=fa[x]) fa[x]=getf(fa[x]); return fa[x]; } int newnode(int x) { nd[tot].v=x; nd[tot].l=0; nd[tot].r=0; nd[tot].dis=0; tot++; return tot-1; } int merge(int x,int y) { if(!x) return y; if(!y) return x; if(nd[x].v<nd[y].v) swap(x,y); nd[x].r=merge(nd[x].r,y); if(nd[nd[x].l].dis<nd[nd[x].r].dis) swap(nd[x].l,nd[x].r); nd[x].dis=nd[nd[x].r].dis+1; return x; } int pop(int x) { int tmp=merge(nd[x].l,nd[x].r); nd[x].dis=nd[x].l=nd[x].r=0; return tmp; } int main() { int i,j,fi,fj,x; while(~scanf("%d",&n)) { tot=1; for(i=1;i<=n;i++) { scanf("%d",&j); fa[i]=newnode(j); } scanf("%d",&m); while(m--) { scanf("%d%d",&i,&j); fi=getf(i); fj=getf(j); if(fi==fj) puts("-1"); else { i=pop(fi); nd[fi].v/=2; j=pop(fj); nd[fj].v/=2; i=merge(i,j); i=merge(i,fi); i=merge(i,fj); fa[i]=fa[fi]=fa[fj]=i; printf("%d ",nd[i].v); } } } return 0; }