HDU 1512 Monkey King(左偏树)

蔚落 2022-06-08 09:51 269阅读 0赞

题目链接:
HDU 1512

题意:
有 n 只猴子,每只猴子都有一个力量,开始时互相都不认识,它们之间发生 m 次争斗,每次发生a,b发生争斗时,a,b会从它们认识的猴子中选出一个最强的,并变为这两只猴子发生争斗,打完之后这两个猴子就互相认识,并且力量减半,如果a,b互相认识就输出−1,否则输出认识的猴子中最大的力量值。

题解:
左偏树。

AC代码:

  1. #include<cstdio>
  2. #include<iostream>
  3. #include<algorithm>
  4. using namespace std;
  5. struct node
  6. {
  7. int l,r;
  8. int dis;
  9. int val;
  10. }ltree[100005];
  11. int par[100005];
  12. int getfather(int x)
  13. {
  14. return par[x] == x?x:par[x]=getfather(par[x]);
  15. }
  16. int merge(int x,int y)//返回合并后的根
  17. {
  18. int l,r;
  19. //插入的树为空时直接返回x (y),也就是合并完的树
  20. if(x==0)return y;
  21. if(y==0)return x;
  22. if(ltree[x].val<ltree[y].val) //大顶堆
  23. {
  24. swap(x,y);
  25. }
  26. ltree[x].r = merge(ltree[x].r,y);//递归合并右子树 和 y
  27. l = ltree[x].l;
  28. r = ltree[x].r;
  29. par[r] = x; //并查集合并,更新右子树的根
  30. if(ltree[l].dis<ltree[r].dis)
  31. {
  32. //必须遵守左偏树的性质,左节点的距离不小于右节点的距离
  33. swap(ltree[x].l,ltree[x].r);
  34. }
  35. if(ltree[x].r==0)//如果没有右子树 则距离为0
  36. {
  37. ltree[x].dis = 0;
  38. }
  39. else ltree[x].dis = ltree[ltree[x].r].dis+1;
  40. return x;
  41. }
  42. int pop(int x)//返回删除根以后左右子树合并的根
  43. {
  44. int l,r;
  45. l = ltree[x].l;
  46. r = ltree[x].r;
  47. //因为要暂时删掉根,所以左右子树先作为根
  48. par[l] = l;
  49. par[r] = r;
  50. ltree[x].l = 0;
  51. ltree[x].r = 0;
  52. ltree[x].dis = 0;
  53. return merge(l,r);
  54. }
  55. int main()
  56. {
  57. int n,m;
  58. while(cin>>n)
  59. {
  60. for(int i=1;i<=n;i++)
  61. {
  62. scanf("%d",&ltree[i].val);
  63. ltree[i].l = 0;
  64. ltree[i].r = 0;
  65. ltree[i].dis = 0;
  66. }
  67. for(int i=1;i<=n;i++)par[i] = i;
  68. scanf("%d",&m);
  69. int a,b;
  70. int fa,fb;
  71. int l,r;
  72. while(m--)
  73. {
  74. scanf("%d%d",&a,&b);
  75. fa = getfather(a);
  76. fb = getfather(b);
  77. if(fa==fb)puts("-1");
  78. else
  79. {
  80. //单挑后减半
  81. ltree[fa].val /= 2;
  82. ltree[fb].val /= 2;
  83. //删除最大的两个值,再与新的值合并
  84. l = pop(fa),r=pop(fb);
  85. l = merge(l,fa);
  86. r = merge(r,fb);
  87. l = merge(l,r);
  88. printf("%d\n",ltree[l].val);
  89. }
  90. }
  91. }
  92. return 0;
  93. }

发表评论

表情:
评论列表 (有 0 条评论,269人围观)

还没有评论,来说两句吧...

相关阅读

    相关

    题目描述 如题,一开始有N个小根堆,每个堆包含且仅包含一个数。接下来需要支持两种操作: 操作1: 1 x y 将第x个数和第y个数所在的小根堆合并(若第x或第y个数...