[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(树上倍增+堆)的更多相关文章

  1. BZOJ3133[Baltic2013]ballmachine

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

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

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

  3. BZOJ5415[Noi2018]归程——kruskal重构树+倍增+堆优化dijkstra

    题目描述 本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定. 魔力之都可以抽象成一个 n 个节点.m 条边的无向连通图(节点的编号从 1 至 n).我们依次用 l,a 描述一条边的长度.海 ...

  4. BZOJ3545&3551[ONTAK2010]Peaks——kruskal重构树+主席树+dfs序+树上倍增

    题目描述 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只 ...

  5. Codevs 2370 小机房的树 LCA 树上倍增

    题目描述 Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上.有一天,他们想爬到一个节点上去搞基,但是作为两只虫子, ...

  6. NOIP2013 货车运输 (最大生成树+树上倍增LCA)

    死磕一道题,中间发现倍增还是掌握的不熟 ,而且深刻理解:SB错误毁一生,憋了近2个小时才调对,不过还好一遍AC省了更多的事,不然我一定会疯掉的... 3287 货车运输 2013年NOIP全国联赛提高 ...

  7. HDU 4822 Tri-war(LCA树上倍增)(2013 Asia Regional Changchun)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4822 Problem Description Three countries, Red, Yellow ...

  8. [NOIP2013/Codevs3287]货车运输-最小[大]生成树-树上倍增

    Problem 树上倍增 题目大意 给出一个图,给出若干个点对u,v,求u,v的一条路径,该路径上最小的边权值最大. Solution 看到这个题第一反应是图论.. 然而,任意路径最小的边权值最大,如 ...

  9. 树上倍增求LCA及例题

    先瞎扯几句 树上倍增的经典应用是求两个节点的LCA 当然它的作用不仅限于求LCA,还可以维护节点的很多信息 求LCA的方法除了倍增之外,还有树链剖分.离线tarjan ,这两种日后再讲(众人:其实是你 ...

随机推荐

  1. 织梦dedecms自定义表单导出到excel教程

    不写死任何字段,不写死任何东西,修改2个文件,让织梦自定义表单自由导出到Excel表格里. 添加教程 1.\dede\templets\diy_main.htm 找到 前台预览</a> 在 ...

  2. chalk插件 使终端输出的字带颜色

    1.使终端输出红色字体: const chalk = require('chalk'); console.log(chalk.red('this is red!') 这时运行终端,打印的this is ...

  3. [luogu]P1800 software_NOI导刊2010提高(06)[DP][二分答案]

    [luogu]P1800 software_NOI导刊2010提高(06) 题目描述 一个软件开发公司同时要开发两个软件,并且要同时交付给用户,现在公司为了尽快完成这一任务,将每个软件划分成m个模块, ...

  4. linux文件夹目录含义及用途

    /boot,存放linux启动文件和内核: /initrd,boot loader initialized RAM disk,就是由boot loader初始化的内存盘.在linux内核启动前,boo ...

  5. 【转】Django之Model层的F对象,Q对象以及聚合函数

    转自:https://blog.csdn.net/wsy_666/article/details/86692050 一.F对象: 作用:用于处理类属性(即model的某个列数据),类属性之间的比较.使 ...

  6. Linux下服务器开发的必要准备

    一.Windows下安装Xshell 二.Linux开启SSH 可以先查询有没有SSH服务 sudo ps -e |grep ssh 没有安装SSH的服务器 sudo apt-get install ...

  7. Loading class `com.mysql.jdbc.Driver'. This is deprecated警告处理,jdbc更新处

    1.报错信息是这样的; 处理:提示信息表明数据库驱动com.mysql.jdbc.Driver'已经被弃用了.应当使用新的驱动com.mysql.cj.jdbc.Driver' 所以,按照提示更改jd ...

  8. Electron-Vue工程初始化,以及需要掌握的相关知识

    1.安装nodejs 下载地址:http://nodejs.cn/ 需要重启系统 2.安装electron npm install electron -g 3.安装vue npm install vu ...

  9. SSH port forwarding: bind: Cannot assign requested address

    https://www.electricmonk.nl/log/2014/09/24/ssh-port-forwarding-bind-cannot-assign-requested-address/

  10. 一、基础篇--1.1Java基础-final, finally, finalize 的区别

    final, finally, finalize 首先,这三个关键字没什么关联,只是放在一起比较像,用法用处完全不同. final: final关键字可以用来修饰类.方法.变量(成员变量和局部变量), ...