要把打架的两堆猴子合并为一堆,查询的又是最大值,所以很容易想到可并堆。
题目要求打完架后战斗力最大的猴子的战斗力要减半,但不能直接在堆中进行这个操作,因为战斗力减半后这只猴子不一定是战斗力最大的猴子了,所以要先把这只猴子从堆中删除,减半后再插入。
#include<complex> #include<cstdio> #include<cstring> using namespace std; const int N=1e5+7; int n,m; int key[N],son[N][2],fat[N],dis[N]; int qread() { int x=0; char ch=getchar(); while(ch<'0' || ch>'9')ch=getchar(); while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} return x; } int Merge(int A,int B) { if(!A || !B)return A+B; if(key[A]<key[B] || (key[A]==key[B] && A>B))swap(A,B); son[A][1]=Merge(son[A][1],B); fat[son[A][1]]=A; if(dis[son[A][1]]>dis[son[A][0]])swap(son[A][1],son[A][0]); dis[A]=dis[son[A][1]]+1; return A; } int Top(int x) { while(fat[x])x=fat[x]; return x; } int Pop(int x) { int l=son[x][0],r=son[x][1]; fat[l]=fat[r]=0; son[x][0]=son[x][1]=dis[x]=0; return Merge(l,r); } int main() { while(scanf("%d",&n)!=EOF) { memset(dis,0,sizeof(dis)); memset(son,0,sizeof(son)); memset(fat,0,sizeof(fat)); for(int i=1;i<=n;i++) key[i]=qread(); scanf("%d",&m); int x,y,r1,r2; while(m--) { x=qread();y=qread(); r1=Top(x);r2=Top(y); if(r1==r2)puts("-1"); else { key[r1]>>=1;key[r2]>>=1; int l=Pop(r1),r=Pop(r2); l=Merge(l,r1);r=Merge(r,r2); printf("%d\n",key[Merge(l,r)]); } } } return 0; }