[BZOJ3133] [Baltic2013]ballmachine(树上倍增+堆)
[BZOJ3133] [Baltic2013]ballmachine(树上倍增+堆)
题面
有一个装球机器,构造可以看作是一棵树。有下面两种操作:
从根放入一个球,只要下方有空位,球会沿着树滚下。如果同时有多个点可以走,那么会选择编号最小的节点所在路径的方向。比如依次在树根4
放2个球,第一个球会落到1
,第二个会落到3
:
从某个位置拿走一个球,那么它上方的球会落下来。比如依次拿走5, 7, 8
三个球:
分析
我们可以预处理出从根节点放第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 ,这两种日后再讲(众人:其实是你 ...
随机推荐
- 织梦dedecms自定义表单导出到excel教程
不写死任何字段,不写死任何东西,修改2个文件,让织梦自定义表单自由导出到Excel表格里. 添加教程 1.\dede\templets\diy_main.htm 找到 前台预览</a> 在 ...
- chalk插件 使终端输出的字带颜色
1.使终端输出红色字体: const chalk = require('chalk'); console.log(chalk.red('this is red!') 这时运行终端,打印的this is ...
- [luogu]P1800 software_NOI导刊2010提高(06)[DP][二分答案]
[luogu]P1800 software_NOI导刊2010提高(06) 题目描述 一个软件开发公司同时要开发两个软件,并且要同时交付给用户,现在公司为了尽快完成这一任务,将每个软件划分成m个模块, ...
- linux文件夹目录含义及用途
/boot,存放linux启动文件和内核: /initrd,boot loader initialized RAM disk,就是由boot loader初始化的内存盘.在linux内核启动前,boo ...
- 【转】Django之Model层的F对象,Q对象以及聚合函数
转自:https://blog.csdn.net/wsy_666/article/details/86692050 一.F对象: 作用:用于处理类属性(即model的某个列数据),类属性之间的比较.使 ...
- Linux下服务器开发的必要准备
一.Windows下安装Xshell 二.Linux开启SSH 可以先查询有没有SSH服务 sudo ps -e |grep ssh 没有安装SSH的服务器 sudo apt-get install ...
- Loading class `com.mysql.jdbc.Driver'. This is deprecated警告处理,jdbc更新处
1.报错信息是这样的; 处理:提示信息表明数据库驱动com.mysql.jdbc.Driver'已经被弃用了.应当使用新的驱动com.mysql.cj.jdbc.Driver' 所以,按照提示更改jd ...
- Electron-Vue工程初始化,以及需要掌握的相关知识
1.安装nodejs 下载地址:http://nodejs.cn/ 需要重启系统 2.安装electron npm install electron -g 3.安装vue npm install vu ...
- SSH port forwarding: bind: Cannot assign requested address
https://www.electricmonk.nl/log/2014/09/24/ssh-port-forwarding-bind-cannot-assign-requested-address/
- 一、基础篇--1.1Java基础-final, finally, finalize 的区别
final, finally, finalize 首先,这三个关键字没什么关联,只是放在一起比较像,用法用处完全不同. final: final关键字可以用来修饰类.方法.变量(成员变量和局部变量), ...