【zoj2334】【左偏树】Monkey King

来源:互联网 发布:wampserver 本地域名 编辑:程序博客网 时间:2024/05/22 01:39

题目大意:

N个猴子,打了M次架,每次打架的时候双方猴子都会派出自己一方战斗力最高的猴子,打完架后这两只猴子的战斗力都减半。同时,不打不相识嘛,两方猴子打完架后就互相认识变成同伙不会再打架。输出每次打架后通过这次冲突合并的那一伙猴子中战斗力最高的猴子的战斗力值,如果冲突双方在同一伙的话直接输出-1就好。


可以使用并查集来维护两个猴子是否互相认识,并且找出它的节点,同时也是战斗值最大的那个猴子,同时将他们的战斗值减半后合并棵左偏树,最后再输出合并后的那一棵左偏树的根节点的战斗值即可。

代码:

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxn = 100000 + 10;struct king{int l,r;int val,dis;}k[maxn];int pre[maxn];int n,m;void init(){freopen("zoj2334.in","r",stdin);freopen("zoj2334.out","w",stdout);}void set_init(){for(int i = 0;i <= n;i++)pre[i] = i;}int find(int x){return x == pre[x] ? x : pre[x] = find(pre[x]);}int merge(int a,int b){if(!a)return b;if(!b)return a;if(k[a].val < k[b].val)swap(a,b);k[a].r = merge(k[a].r,b);pre[k[a].r] = a;if(k[k[a].l].dis < k[k[a].r].dis)swap(k[a].l,k[a].r);if(k[a].r == 0)k[a].dis = 0;else k[a].dis = k[k[a].r].dis + 1;return a;}int process(int a,int b){int x = find(a),y = find(b);if(x == y)return -1;k[x].val /= 2;int tmp = merge(k[x].l,k[x].r);k[x].l = k[x].r = k[x].dis = 0;int xroot = merge(tmp,x);k[y].val /= 2;tmp = merge(k[y].l,k[y].r);k[y].l = k[y].r = k[y].dis = 0;int yroot = merge(tmp,y);tmp = merge(xroot,yroot);return k[tmp].val;}void readdata(){while(scanf("%d",&n) != EOF){memset(k,0,sizeof(k));set_init();for(int i = 1;i <= n;i++)scanf("%d",&k[i].val);scanf("%d",&m);for(int i = 1;i <= m;i++){int a,b;scanf("%d%d",&a,&b);int ans = process(a,b);printf("%d\n",ans);}}}int main(){init();readdata();return 0;}