• treap树:hdu 4585 Shaolin


    题目链接如下所示:

    Problem - 4585

    大意就是:

    有个和尚战斗力1e9,id是1。输入n代表n个和尚,接下来n行每行一个id加战斗力,按空格分割。

    输出就是找到在他入少林寺之前和他最近的战斗力和尚的id,然后把自身的id和对应找到的和尚id按行输出。

    这里主要问题就是对战斗力排序,然后找到最近的那个战斗力的对应id,然后输出。

    1.std的map

    思路很简单,就是存一个的map,然后每次去找和他最相近的那个grade对应的id,这里注意的是题目给的范围,grade不可能超过第一个和尚的grade,因此新插入的位置只可能在第一个和尚之前,而第一个和尚是最后那个战斗力最强的。

    代码如下所示:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. using namespace std;
    9. map<int, int> mp;
    10. int id,grade,ans;
    11. int main()
    12. {
    13. int n;
    14. while (~scanf("%d",&n) && n){
    15. mp.clear();
    16. mp[1000000000]=1;
    17. while (n--){
    18. scanf("%d %d",&id, &grade);
    19. mp[grade]=id;
    20. map<int, int>::iterator it=mp.find(grade);
    21. if (it==mp.begin()){
    22. ans=(++it)->second;
    23. }else{
    24. map<int, int>::iterator it2=it;
    25. it2--;
    26. it++;
    27. // cout<<"it:"<second<<",it2:"<second<
    28. ans = grade-it2->first <= it->first-grade ? it2->second : it->second;
    29. }
    30. printf("%d %d\n",id, ans);
    31. }
    32. }
    33. return 0;
    34. }

    2.手敲treap

    有篇博客把treap树讲的非常的清楚,包括了有旋treap的插入删除以及求前驱后继操作等等以及无旋treap树的合并与分裂操作。

    数据结构-Treap(树堆) 详解_12362287的技术博客_51CTO博客

    这里我们要做的其实就是treap的插入,由于有插入操作我们要维护堆,所以就要基于随机的优先级进行旋转,其次还要实现找到武功值为g的位次k,然后查找位次k-1,k+1的对应的武功值。

    总的思路如下:

    1.接受k,g,即id和武功值

    2.维护id[g]=k,插入g到treap树中

    3.查找g在树中的位次t

    4.查找t-1,t+1位次对应的数值

    5.输出答案

    代码如下所示:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. using namespace std;
    11. const int N=5000001;
    12. int id[N];
    13. struct Node{
    14. int size;//以当前节点为根的子树的大小
    15. int rank;//用以维护treap的随机数
    16. int key;//键值 这里是武功级别
    17. Node *son[2];
    18. // 小于比较 自身rank和传入的rank
    19. bool operator < (const Node &a) const{
    20. return rank
    21. }
    22. // 比较x和自身key
    23. // 相等返回-1
    24. // x
    25. // x>key 右子树 1
    26. int cmp(int x) const{
    27. if (key==x) return -1;
    28. return x0:1;
    29. }
    30. // 更新子树的大小 旋转时treap存在节点需要更新子树大小
    31. void update(){
    32. size=1;
    33. if (son[0]) size+=son[0]->size;
    34. if (son[1]) size+=son[1]->size;
    35. }
    36. };
    37. // 旋转 d=0左旋 d=1右旋
    38. void rotate(Node* &o,int d){
    39. Node *k=o->son[1^d];
    40. o->son[1^d]=k->son[d];
    41. k->son[d]=o;
    42. o->update();
    43. k->update();
    44. o=k;//这里把原来指向o的位置改了 所以原来指向o的指针现在相当于指向k 也是传指针的引用的原因
    45. }
    46. void insert(Node* &o, int x){
    47. if (!o){
    48. o=new Node();//直接在原位置创建指针 这是穿指针的引用的原因
    49. o->son[0]=o->son[1]=nullptr;
    50. o->rank=rand();
    51. o->key=x;
    52. o->size=1;
    53. }else{
    54. int d=o->cmp(x);
    55. insert(o->son[d],x);
    56. o->update();
    57. if (oson[d]){
    58. rotate(o,1^d);
    59. }
    60. }
    61. }
    62. // 返回第k大的数
    63. int kth(Node* o, int k){
    64. if (o== nullptr||k<0 || k>o->size){
    65. return -1;
    66. }
    67. int s= (o->son[1] == nullptr) ? 0 : o->son[1]->size;
    68. if (k==s+1) return o->key;
    69. else if (k1){
    70. return kth(o->son[1], k);
    71. }else{
    72. return kth(o->son[0],k-s-1);
    73. }
    74. }
    75. // 找到k的位次
    76. int find(Node* o, int k){
    77. if (!o) return -1;
    78. int d=o->cmp(k);
    79. if (d==-1){
    80. return o->son[1] == nullptr ? 1 : o->son[1]->size+1;
    81. }else if (d==1){
    82. return find(o->son[1], k);
    83. }else{
    84. int tmp=find(o->son[0], k);
    85. if (tmp==-1) return -1;
    86. return o->son[1] == nullptr ? tmp+1 : tmp+o->son[1]->size+1;
    87. }
    88. }
    89. void deleteNode(Node *root){
    90. if (!root) return;
    91. deleteNode(root->son[0]);
    92. deleteNode(root->son[1]);
    93. delete root;
    94. }
    95. int main()
    96. {
    97. int n;
    98. while (scanf("%d", &n) && n){
    99. srand(time(nullptr));
    100. int k,g;
    101. Node *root = new Node();
    102. scanf("%d %d",&k,&g);
    103. // cout<
    104. id[g]=k;
    105. root->son[0]=root->son[1]=nullptr;
    106. root->key=g;
    107. root->size=1;
    108. root->rank=rand();
    109. printf("%d %d\n",k,1);
    110. for (int i = 2; i <= n; ++i) {
    111. scanf("%d %d",&k,&g);
    112. // cout<
    113. id[g]=k;
    114. // cout<<0<
    115. insert(root, g);
    116. // cout<<1<
    117. int t= find(root, g);
    118. // cout<<2<
    119. int ans,ans1,ans2;
    120. ans1=kth(root, t-1);
    121. ans2=kth(root, t+1);
    122. if (ans1!=-1 && ans2!=-1){
    123. ans= ans1-g >= g-ans2 ? ans2 : ans1;
    124. }else if (ans1==-1){
    125. ans=ans2;
    126. }else{
    127. ans=ans1;
    128. }
    129. printf("%d %d\n", k,id[ans]);
    130. }
    131. deleteNode(root);
    132. }
    133. return 0;
    134. }

  • 相关阅读:
    一个最简verilog代码的分析
    基于Qt的Live2D模型显示以及控制
    PAT 1008 Elevator
    Allegro走线自动关闭其它飞线操作指导
    【SpringBoot+Vue】前后端分离项目之图片上传与下载
    信息学奥赛一本通 1368:对称二叉树(tree_c)
    OS2.3.2:进程互斥的软件实现方法
    【云原生 | Kubernetes 系列】---Consul 安装配置
    Dubbo 环境隔离
    数据结构算法之——时间复杂度和空间复杂度
  • 原文地址:https://blog.csdn.net/weixin_46266058/article/details/127833940