[BZOJ3133] [Baltic2013]ballmachine(树上倍增+堆)
[BZOJ3133] [Baltic2013]ballmachine(树上倍增+堆)
题面
有一个装球机器,构造可以看作是一棵树。有下面两种操作:
从根放入一个球,只要下方有空位,球会沿着树滚下。如果同时有多个点可以走,那么会选择编号最小的节点所在路径的方向。比如依次在树根4放2个球,第一个球会落到1,第二个会落到3:
.jpg)
从某个位置拿走一个球,那么它上方的球会落下来。比如依次拿走5, 7, 8三个球:
.jpg)
分析
我们可以预处理出从根节点放第i个球时,球到达的位置x.因此,对于每个节点x,我们记录放第几个球的时候才能落到x,记为seq[x]。
预处理的时候先dfs一遍,求出每个节点子树中的最小节点编号。然后再dfs一遍,按照子树中的最小节点编号从小到大遍历。实现上直接sort一遍邻接表即可。容易发现,seq[x]就是x在树的后序遍历序列中处在第几个(因为球会尽量往最下方走)
void dfs2(int x,int fa){
for(int i=0;i<(int)E[x].size();i++){//E[x]已经排过序
int y=E[x][i];
if(y!=fa){
dfs2(y,x);
}
}
seq[x]=++tim;
hash_seq[seq[x]]=x;
}
然后考虑动态插入和删除。
维护一个最小堆,满足堆顶元素seq最小。插入的时候弹出堆顶,把堆顶对应的节点的状态标记为有球。
删除节点x的时候,x到根节点链上的节点会往下落一层。因此只需要用树上倍增找到x祖先里深度最浅的有球节点,将它的状态标记为无球,然后插入最小堆.
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<vector>
#include<algorithm>
#define maxn 100000
#define maxlogn 21
using namespace std;
int n,m;
int root;
vector<int>E[maxn+5];
int log2n;
int min_id[maxn+5];//子树中节点的最小编号
int anc[maxn+5][maxlogn+5];
int deep[maxn+5];
bool cmp(int x,int y){
return min_id[x]<min_id[y];
}
void dfs1(int x,int fa){
min_id[x]=x;
deep[x]=deep[fa]+1;
anc[x][0]=fa;
for(int i=1;i<=log2n;i++) anc[x][i]=anc[anc[x][i-1]][i-1];
for(int i=0;i<(int)E[x].size();i++){
int y=E[x][i];
if(y!=fa){
dfs1(y,x);
min_id[x]=min(min_id[x],min_id[y]);
}
}
}
int tim;
int seq[maxn+5]; //掉球顺序
int hash_seq[maxn+5];//seq=i的节点编号
int is_ball[maxn+5];//是否有球
priority_queue<int,vector<int>,greater<int> >q;//按落球顺序从小到大,存储没有球的节点
void dfs2(int x,int fa){
for(int i=0;i<(int)E[x].size();i++){
int y=E[x][i];
if(y!=fa){
dfs2(y,x);
}
}
seq[x]=++tim;
hash_seq[seq[x]]=x;
}
int insert(int num){
int ans;
for(int i=1;i<=num;i++){
int x=hash_seq[q.top()];
q.pop();
is_ball[x]=1;
if(i==num){
ans=x;
break;
}
}
return ans;
}
int del(int x){
int orig_x=x;
for(int i=log2n;i>=0;i--){
if(is_ball[anc[x][i]]) x=anc[x][i];
}
is_ball[x]=0;
q.push(seq[x]);
return deep[orig_x]-deep[x];
}
int main(){
int f;
int op,num;
scanf("%d %d",&n,&m);
log2n=log2(n)+1;
for(int i=1;i<=n;i++){
scanf("%d",&f);
if(f==0) root=i;
else E[f].push_back(i);
}
dfs1(root,0);
for(int i=1;i<=n;i++) sort(E[i].begin(),E[i].end(),cmp);
dfs2(root,0);
for(int i=1;i<=n;i++) q.push(seq[i]);
for(int i=1;i<=m;i++){
scanf("%d %d",&op,&num);
if(op==1) printf("%d\n",insert(num));
else printf("%d\n",del(num));
}
}
[BZOJ3133] [Baltic2013]ballmachine(树上倍增+堆)的更多相关文章
- BZOJ3133[Baltic2013]ballmachine
题目描述 https://www.lydsy.com/JudgeOnline/problem.php?id=3133 题解 还是分两个操作来说吧. 先看第一个操作,放球,可以发现,对于祖先节点和后代节 ...
- 【BZOJ 3133】 3133: [Baltic2013]ballmachine (线段树+倍增)
3133: [Baltic2013]ballmachine Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 148 Solved: 66 Descri ...
- BZOJ5415[Noi2018]归程——kruskal重构树+倍增+堆优化dijkstra
题目描述 本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定. 魔力之都可以抽象成一个 n 个节点.m 条边的无向连通图(节点的编号从 1 至 n).我们依次用 l,a 描述一条边的长度.海 ...
- BZOJ3545&3551[ONTAK2010]Peaks——kruskal重构树+主席树+dfs序+树上倍增
题目描述 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只 ...
- Codevs 2370 小机房的树 LCA 树上倍增
题目描述 Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上.有一天,他们想爬到一个节点上去搞基,但是作为两只虫子, ...
- NOIP2013 货车运输 (最大生成树+树上倍增LCA)
死磕一道题,中间发现倍增还是掌握的不熟 ,而且深刻理解:SB错误毁一生,憋了近2个小时才调对,不过还好一遍AC省了更多的事,不然我一定会疯掉的... 3287 货车运输 2013年NOIP全国联赛提高 ...
- HDU 4822 Tri-war(LCA树上倍增)(2013 Asia Regional Changchun)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4822 Problem Description Three countries, Red, Yellow ...
- [NOIP2013/Codevs3287]货车运输-最小[大]生成树-树上倍增
Problem 树上倍增 题目大意 给出一个图,给出若干个点对u,v,求u,v的一条路径,该路径上最小的边权值最大. Solution 看到这个题第一反应是图论.. 然而,任意路径最小的边权值最大,如 ...
- 树上倍增求LCA及例题
先瞎扯几句 树上倍增的经典应用是求两个节点的LCA 当然它的作用不仅限于求LCA,还可以维护节点的很多信息 求LCA的方法除了倍增之外,还有树链剖分.离线tarjan ,这两种日后再讲(众人:其实是你 ...
随机推荐
- TeamViewer的替代品:realVNC
TeamViewer的替代品:realVNC official web: realvnc: https://www.realvnc.com/ steps: 在需要被控制的PC上装上realVNC的服务 ...
- weblogic 10c and 12c 打补丁
https://pan.baidu.com/s/17IaK1SYwHxwt-CRb0zDqXw
- 如何查看 mysql 的视图?
1.查询表(包括view) mysql> use iips; Database changed mysql> show tables; +------------------------- ...
- 记ubuntu sudo无法使用,su密码不对的解决办法
前言 因为我有强制关机的习惯, 然后就杯具了.. ubuntu版本是 16.04 sudo没法使用, su密码不对, 顿时我就慌了 解决方案 1.1.开机点击ESC,进去GUN GRUB界面 1.2. ...
- 【UOJ #210】【UER #6】寻找罪犯
题目描述 通过一些不可描述的方式,妹滋滋算出了 51% 的得票率,于是就她就把这个公开给了广大用户 —— UOJ 解散已成定局. 几个小时后,UOJ 创始人伏特跳蚤国王宣布辞职,即日起退出 UOJ 团 ...
- CSS 处理溢出强行换行
CSS折行样式 word-break:break-all;允许单词拆分折行 word-break:keep-all;只能在半角空格或连字符处换行. word-wrap:break-word;在长单词或 ...
- sqli-labs(34)
0x01构造闭合 同样 发现 ’被注释掉了 试探了一波发现什么信息都不会返回 正确错误的页面都一样 之前我们的方法就是将过滤函数添加的 \ 给吃掉.而get型的方式我们是以url形式提交的,因此数据会 ...
- [CSP-S模拟测试]:简单的括号序列(组合数)
题目传送门(内部题82) 输入格式 一行一个字符串$ss$,保证$ss$中只包含$'('$和$')'$. 输出格式 一行一个整数,表示满足要求的子序列数对$10^9+7$的结果. 样例 样例输入1: ...
- vue 在移动端实现红包雨 (兼容性好)
下面是代码:<template> <div class="ser_home"> <ul class="red_packe ...
- springboot+druid+mybatis-Plus 配置详解
网上找了很多关于springboot+druid+mybatis-Plus的配置,遇见的很多问题 也没找到好的解决方案.折腾了好几天终于自己配置通过了. springboot的pom文件 <pa ...