题目描述

有一个装球机器,构造可以看作是一棵树。有下面两种操作:

  • 从根放入一个球,只要下方有空位,球会沿着树滚下。如果同时有多个点可以走,那么会选择编号最小的节点所在路径的方向。比如依次在树根4放2个球,第一个球会落到1,第二个会落到3
  • 从某个位置拿走一个球,那么它上方的球会落下来。比如依次拿走5, 7, 8三个球:

输入

第一行:球的个数N,操作个数Q (N, Q <= 100 000)下面N行:第i个节点的父亲。如果是根,则为0 接下来Q行:op num

  1. op == 1:在根放入num个球
  2. op == 2:拿走在位置num的球

输出

保证输入合法

  1. op == 1:输出最后一个球落到了哪里
  2. op == 2:输出拿走那个球后有多少个球会掉下来

样例输入

8 4
0
1
2
2
3
3
4
6
1 8
2 5
2 7
2 8

样例输出

1
3
2
2

这道题有两个操作,删球和加球,对于1操作,可以发现两个特性:1、对于一个节点,它下面的节点没填满,这个节点不会被填上。2、对于一个节点,它子树最小编号的子树没填满,其他子树不会被填球。那么就可以以子树最小编号的大小为顺序维护一个dfs序,在dfs序上,如果前面的位置没填满,后面的位置不会被填。如果因为删除而导致一段被填满的区间中有节点空缺,可以用小根堆(也可以优先队列)来每次取优先度最大的插入。删除操作就是删除一个节点上的球,然后这的节点到根节点链上所有球都向下落一层,也可以看作是把链上最上面有球的节点的球删掉,那么只要找到距离根最近的有球节点就行,但如果一层一层往上爬显然时间复杂度太高,所以需要倍增往上跳。
最后附上代码.
  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<iostream>
  4. #include<cmath>
  5. #include<cstring>
  6. #include<vector>
  7. #include<queue>
  8. using namespace std;
  9. priority_queue< int,vector<int>,greater<int> >q;
  10. vector<int>v[200010];
  11. int n,Q;
  12. int f[20][200010];//倍增祖先
  13. int m[200010];//子树最小的编号
  14. int s[200010];//优先度
  15. int r[200010];//优先度对应节点
  16. int cnt;
  17. int root;
  18. int x,y;
  19. int opt;
  20. int d[200010];//深度
  21. int vis[200010];//是否被填标记
  22. bool cmp(int x,int y)
  23. {
  24. return m[x]<m[y];
  25. }
  26. void dfs(int x)//按子树最小编号大小排序并处理深度
  27. {
  28. m[x]=x;
  29. for(int i=0;i<v[x].size();i++)
  30. {
  31. f[0][v[x][i]]=x;
  32. d[v[x][i]]=d[x]+1;
  33. dfs(v[x][i]);
  34. m[x]=min(m[x],m[v[x][i]]);
  35. }
  36. sort(&v[x][0],&v[x][v[x].size()],cmp);
  37. }
  38. void getsign(int x)//处理优先度
  39. {
  40. for(int i=0;i<v[x].size();i++)
  41. {
  42. getsign(v[x][i]);
  43. }
  44. s[x]=++cnt;
  45. r[cnt]=x;
  46. }
  47. int main()
  48. {
  49. scanf("%d%d",&n,&Q);
  50. for(int i=1;i<=n;i++)
  51. {
  52. scanf("%d",&x);
  53. if(x==0)
  54. {
  55. root=i;
  56. }
  57. else
  58. {
  59. v[x].push_back(i);
  60. }
  61. }
  62. for(int i=1;i<=n;i++)
  63. {
  64. q.push(i);
  65. }
  66. d[root]=1;
  67. dfs(root);
  68. getsign(root);
  69. for(int i=1;i<=20;i++)
  70. {
  71. for(int j=1;j<=n;j++)
  72. {
  73. f[i][j]=f[i-1][f[i-1][j]];
  74. }
  75. }
  76. while(Q--)
  77. {
  78. scanf("%d%d",&opt,&x);
  79. if(opt==1)
  80. {
  81. while(x--)
  82. {
  83. y=r[q.top()];
  84. q.pop();
  85. vis[y]=1;
  86. }
  87. printf("%d\n",y);
  88. }
  89. else
  90. {
  91. int fa=x;
  92. for(int i=20;i>=0;i--)
  93. {
  94. if(vis[f[i][x]]==1)
  95. {
  96. x=f[i][x];
  97. }
  98. }
  99. vis[x]=0;
  100. printf("%d\n",d[fa]-d[x]);
  101. q.push(s[x]);
  102. }
  103. }
  104. }

BZOJ3133[ballmachine]——倍增+优先队列的更多相关文章

  1. CF786C-Till I Collapse【树状数组倍增,优先队列】

    正题 题目链接:https://www.luogu.com.cn/problem/CF786C 题目大意 给出一个长度为\(n\)的序列. 对于每个\(k\in[1,n]\)求将\(n\)分成最少的段 ...

  2. [BZOJ3133] [Baltic2013]ballmachine(树上倍增+堆)

    [BZOJ3133] [Baltic2013]ballmachine(树上倍增+堆) 题面 有一个装球机器,构造可以看作是一棵树.有下面两种操作: 从根放入一个球,只要下方有空位,球会沿着树滚下.如果 ...

  3. bzoj4458 GTY的OJ (优先队列+倍增)

    把超级钢琴放到了树上. 这次不用主席树了..本来以为会好写一点没想到细节更多(其实是树上细节多) 为了方便,对每个点把他的那个L,R区间转化成两个深度a,b,表示从[a,b)选一个最小的前缀和(到根的 ...

  4. 【BZOJ 3133】 3133: [Baltic2013]ballmachine (线段树+倍增)

    3133: [Baltic2013]ballmachine Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 148  Solved: 66 Descri ...

  5. [Baltic2013]ballmachine BZOJ3133

    分析: 我们考虑,因为每次放置的时候,都是向子树中含有的编号最小的哪一个走,那么放置的顺序是固定的,我们将边以to的子树最小排序,之后得到的出栈序就是球的放入顺序.目测可以使用堆来实现,线段树也能实现 ...

  6. BZOJ3133[Baltic2013]ballmachine

    题目描述 https://www.lydsy.com/JudgeOnline/problem.php?id=3133 题解 还是分两个操作来说吧. 先看第一个操作,放球,可以发现,对于祖先节点和后代节 ...

  7. Problem 1016 咒文卷轴 优先队列+前缀和+rmq

    题目链接: 题目 Problem 1016 咒文卷轴 Time Limit: 3000 mSec Memory Limit : 131072 KB 问题描述 小Y 是一个魔法师,有一天他获得了一卷神秘 ...

  8. BZOJ 4144 Dijkstra+Kruskal+倍增LCA

    思路: 先把所有的加油站 push进按weight排序的优先队列里 对于每个不是加油站的点 找到到它的点的最短路以及它来源的加油站 如果x和y有边 且x和y加油站的来源不一样 则它可以连边 跑一边Kr ...

  9. PAT1057 Stack(树状数组+倍增)

    目录 题目大意 题目分析 题目大意 要求维护一个栈,提供压栈.弹栈以及求栈内中位数的操作(当栈内元素\(n\)为偶数时,只是求第\(n/2\)个元素而非中间两数的平均值).最多操作100000次,压栈 ...

随机推荐

  1. DOM(三)

    Text类型 文本节点由Text类型表示,包含的是可以照字面解释的纯文本内容,纯文本中可以包含转义后的HTML字符,但不包含HTML代码,Text节点具有以下特征: nodeType值为3: node ...

  2. Gradle构建工具从入门到精通(IDEA)

    1.Gradle安装 官网下载压缩包,然后解压,配置本地环境变量.主要有下面两个: GRADLE_HOME 是解压后的目录, GRADLE_USER_HOME 的作用是让其他程序检测到本地.gradl ...

  3. 单链表的基本操作--c++

    #include <iostream> //实现单链表的建立,测长和打印 #include <string> using namespace std; struct node ...

  4. Full Regularization Path for Sparse Principal Component Analysis

    目录 背景 Notation Sparse PCA Semidefinite Relaxation Low Rank Optimization Sorting and Thresholding 背景 ...

  5. Linux安装Apache常见报错(一)

    启动Apache提示报错:Could not reliably determine the server's fully qualified domain name, using localhost, ...

  6. 【转】mysql热备

    mysql双机热备的实现 亲测可用

  7. iOS中的截屏(屏幕截屏及scrollView或tableView的全部截屏)

    iOS中的截屏(屏幕截屏及scrollView或tableView的全部截屏) 2017.03.16 12:18* 字数 52 阅读 563评论 4喜欢 2 1. 截取屏幕尺寸大小的图片并保存至相册 ...

  8. [转帖]分布式Unique ID的生成方法一览

    分布式Unique ID的生成方法一览 http://www.importnew.com/22211.html 分布式的Unique ID的用途如此广泛,从业务对象Id到日志的TraceId,本文总结 ...

  9. emplace与insert的区别(C++11)

    转自时习之 C++11中大部分的容器对于添加元素除了传统的 insert 或者 pusb_back/push_front 之外都提供一个新的函数叫做 emplace. 比如如果你想要向 std::ve ...

  10. YAML配置:mapping values are not allowed here

    在配置Eureka服务器配置文件的时候,出现了mapping values not allowed here的错误,原因是的冒号 ”:“后面没有空格. 原因分析:yml文件中,键值对是以": ...