thinking:1、可以为大根堆或者小根堆,相当于优先队列,但是有合并这个功能
关键代码是
int merge(int x,int y){
if(tree[x].weight==0)return y;
if(tree[y].weight==0)return x;
if(tree[x].weight<tree[y].weight)swap(x,y); //只是改变x与y的数字
tree[x].rch=merge(tree[x].rch,y);
swap(x,y);
return x;
}
通过把2个斜堆的根结点对比,求大的或小的放在根结点,然后交换其子结点,递归操作。
代码:
#include <bits/stdc++.h>
using namespace std;
struct ttt{
int weight,lch,rch;
};
ttt tree[100000+5];
int n;
int pre[100000+5];
void init1(){
for(int i=1;i<=n;i++)
pre[i]=i;
// cout << pre[i] << endl;}
}
int find(int x){
while(x!=pre[x])
x=pre[x];
return x;
}
int merge(int x,int y){
if(tree[x].weight==0)return y;
if(tree[y].weight==0)return x;
if(tree[x].weight<tree[y].weight)swap(x,y); //只是改变x与y的数字
tree[x].rch=merge(tree[x].rch,y);
swap(tree[x].lch,tree[y].rch);
return x;
}
int fun(int t1,int t2){
int x=find(t1),y=find(t2);
if(x==y)return -1;
int ans,xx,yy,tt;
tt=tree[x].weight>tree[y].weight?tree[x].weight:tree[y].weight;
ans=merge(tree[x].lch,tree[x].rch); //将其根节点的左右2个节点再合并。
tree[x].weight/=2;
tree[x].rch=tree[x].lch=0;
xx=merge(x,ans);
tree[y].weight/=2;
ans=merge(tree[y].lch,tree[y].rch); //将其根节点的左右两个节点再合并,此时的ans为根结点,最大或最小
tree[y].rch=tree[y].lch=0;
yy=merge(y,ans);
int p=merge(xx,yy); //并查集思想,前驱就是他们的根节点
pre[xx]=pre[yy]=pre[x]=pre[y]=pre[t1]=pre[t2]=p;
return tt/2;
}
int main(){
freopen("in.txt","r",stdin);
memset(tree,0,sizeof(tree));
int m,i,j,k,l,f1,f2;
cin >> n;
init1();
for(i=1;i<=n;i++)
cin >> tree[i].weight;
cin >> m;
for(i=1;i<=m;i++){
cin >> f1 >> f2;
// cout << find(f1) << find(f2) << endl;
int g=fun(f1,f2);
cout << g<< endl;}
return 0;
}