3133: [Baltic2013]ballmachine

Time Limit: 20 Sec  Memory Limit: 128 MB
Submit: 148  Solved: 66

Description

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

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

Input

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

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

Output

保证输入合法

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

Sample Input

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

Sample Output

1
3
2
2

HINT

Source

【分析】

  没什么人发题解。。

  像我一样看错题的同学看看discuss。。【可怜我只看了样例,然后出的数据对拍的全是祖先的id小于儿子的,就什么也没发现。。

  首先,按照收球顺序弄到dfn,然后每次就是问没有放球的dfn最小的嘛,就用线段树搞这个就好了。【一开始想二分+前缀和logn^2真是很搞笑。。

  第二个拿东西,就是相当于把x往上走最后一个有东西的放到x那里,掉了多少个就用dep求,这个我用倍增搞的。

  就这样啊。不要看错题就好了啊。

 #include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
#define Maxn 100010 int mymin(int x,int y) {return x<y?x:y;} struct node
{
int x,y,next;
}t[Maxn*];
int first[Maxn],len; void ins(int x,int y)
{
t[++len].x=x;t[len].y=y;
t[len].next=first[x];first[x]=len;
} int dfn[Maxn],fn[Maxn],c[Maxn],fa[Maxn],dep[Maxn],mn[Maxn],cnt=;
int ff[Maxn][];
bool p[Maxn]; void dfs1(int x)
{
mn[x]=x;
for(int i=first[x];i;i=t[i].next) if(t[i].y!=fa[x])
{
int y=t[i].y;
dfs1(y);
mn[x]=mymin(mn[x],mn[y]);
}
} bool cmp(int x,int y) {return mn[x]<mn[y];} int son[Maxn];
void dfs(int x)
{
dep[x]=dep[fa[x]]+;
int st=son[],ed;
for(int i=first[x];i;i=t[i].next) if(t[i].y!=fa[x])
{
int y=t[i].y;
son[++son[]]=y;
}ed=son[];
sort(son+st+,son++ed,cmp);
for(int i=st+;i<=ed;i++) dfs(son[i]);
dfn[x]=++cnt;
fn[cnt]=x;
} struct nnode
{
int l,r,lc,rc,sm;
}tr[Maxn*]; int tot=;
int build(int l,int r)
{
int x=++tot;
tr[x].l=l;tr[x].r=r;tr[x].sm=;
if(l!=r)
{
int mid=(l+r)>>;
tr[x].lc=build(l,mid);
tr[x].rc=build(mid+,r);
}
else tr[x].lc=tr[x].rc=;
return x;
} void change(int x,int y,int z)
{
if(tr[x].l==tr[x].r)
{
tr[x].sm=z;
return;
}
int mid=(tr[x].l+tr[x].r)>>;
if(y<=mid) change(tr[x].lc,y,z);
else change(tr[x].rc,y,z);
tr[x].sm=tr[tr[x].lc].sm+tr[tr[x].rc].sm;
} int query(int x)
{
if(tr[x].l==tr[x].r) return tr[x].l;
int lc=tr[x].lc,rc=tr[x].rc;
int mid=(tr[x].l+tr[x].r)>>;
if(tr[lc].sm<mid-tr[x].l+) return query(tr[x].lc);
return query(tr[x].rc);
} int ffind(int x)
{
for(int j=;j>=;j--) if(ff[x][j]&&p[ff[x][j]])
x=ff[x][j];
return x;
} int main()
{
int n,q;
scanf("%d%d",&n,&q);
len=;
memset(first,,sizeof(first));
int rt=;
for(int i=;i<=n;i++)
{
int x;
scanf("%d",&x);
fa[i]=x;
if(x==) rt=i;
else ins(x,i);
}
for(int i=;i<=n;i++) ff[i][]=fa[i];
for(int i=;i<=n;i++) p[i]=;
for(int j=;(<<j)<=n;j++)
for(int i=;i<=n;i++)
ff[i][j]=ff[ff[i][j-]][j-];
dep[]=;
dfs1(rt);
son[]=;dfs(rt);
build(,n);
for(int i=;i<=q;i++)
{
int op,x;
scanf("%d%d",&op,&x);
if(op==)
{
while(x--)
{
int y=query();
change(,y,);
p[fn[y]]=;
if(x==) printf("%d\n",fn[y]);
}
}
else
{
if(!p[x]) continue;
int y=ffind(x);
change(,dfn[y],-);
p[y]=;
printf("%d\n",dep[x]-dep[y]);
}
}
return ;
}

2017-03-26 20:30:43

【BZOJ 3133】 3133: [Baltic2013]ballmachine (线段树+倍增)的更多相关文章

  1. bzoj 3779: 重组病毒 LCT+线段树+倍增

    题目: 黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒.这种病毒的繁殖和变异能力极强.为了阻止这种病毒传播,某安全机构策划了一次实验,来研究这种病毒. 实验在一个封闭 ...

  2. isaster(Comet OJ - Contest #11D题+kruskal重构树+线段树+倍增)

    目录 题目链接 思路 代码 题目链接 传送门 思路 \(kruskal\)重构树\(+\)线段树\(+\)倍增 代码 #include <set> #include <map> ...

  3. [BZOJ 1483] [HNOI2009] 梦幻布丁 (线段树合并)

    [BZOJ 1483] [HNOI2009] 梦幻布丁 (线段树合并) 题面 N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1 ...

  4. [BZOJ 2653] middle(可持久化线段树+二分答案)

    [BZOJ 2653] middle(可持久化线段树+二分答案) 题面 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整. 给你一个长度为n的序 ...

  5. bzoj 1537: [POI2005]Aut- The Bus 线段树

    bzoj 1537: [POI2005]Aut- The Bus 先把坐标离散化 设f[i][j]表示从(1,1)走到(i,j)的最优解 这样直接dp::: f[i][j] = max{f[i-1][ ...

  6. [BZOJ 3196] 213平衡树 【线段树套set + 树状数组套线段树】

    题目链接:BZOJ - 3196 题目分析 区间Kth和区间Rank用树状数组套线段树实现,区间前驱后继用线段树套set实现. 为了节省空间,需要离线,先离散化,这样需要的数组大小可以小一些,可以卡过 ...

  7. 【UOJ295】【ZJOI2017】线段树 倍增

    题目大意 http://uoj.ac/problem/295 题解 考虑像 zkw 线段树一样,从 \([l-1,l-1],[r+1,r+1]\) 这两个区间开始往上跳,直到两个指针碰到一起为止. 先 ...

  8. 2019.03.26 bzoj4444: [Scoi2015]国旗计划(线段树+倍增)

    传送门 题意简述:现在给你一个长度为mmm的环,有nnn条互不包含的线段,问如果强制选第iii条线段至少需要用几条线段覆盖这个环,注意用来的覆盖的线段应该相交,即[1,3],[4,5][1,3],[4 ...

  9. BZOJ.5286.[AHOI/HNOI2018]转盘(线段树)

    BZOJ LOJ 洛谷 如果从\(1\)开始,把每个时间\(t_i\)减去\(i\),答案取决于\(\max\{t_i-i\}\).记取得最大值的位置是\(p\),答案是\(t_p+1+n-1-p=\ ...

随机推荐

  1. lazyload support for Zepto.js

    关于lazyload,很久之前整理过它的文档:<Lazy Load(1.7.0)中文文档 -- 延迟加载图片的jQuery插件> 因为懒,所以才要用lazyload.但lazyload用了 ...

  2. 使用Forms Authentication

    using System; using System.Web; using System.Web.Security;   namespace AuthTest {   public class Aut ...

  3. CodeForces - 1004C

    Since Sonya is interested in robotics too, she decided to construct robots that will read and recogn ...

  4. Hadoop笔记之搭建环境

    Hadoop的环境搭建分为单机模式.伪分布式模式.完全分布式模式. 因为我的本本比较挫,所以就使用伪分布式模式. 安装JDK 一般Linux自带的Java运行环境都是Open JDK,我们到官网下载O ...

  5. 带你优雅的使用 icon

    前言 本篇文章其实陆陆续续写了快半年,主体部分写好了很久了,但由于种种原因一直没有发布.首先来说说写这篇文章的主要初衷是:在做前端后台项目的时候经常会用到很多 icon 图标,刚开始还好,但随着项目的 ...

  6. scandir函数的研究【笔记】

    以下是本人的学习笔记,代码并非原创,均摘自官方源码,贴出来仅供学习记录用 scandir 的使用要注意内存泄漏的问题 scandir函数实现: vi ./uClibc-0.9.33.2/libc/mi ...

  7. MGR Switch single-Primary to Muti_primary

    MGR single_primary 切换 Muti-Primary 模式 root@localhost [(none)]>select * from performance_schema.re ...

  8. java的loadrunner脚本案例

    /* * LoadRunner Java script. (Build: 670) *  * ״̬£º²¢·¢²âÊÔͨ¹ý * ²âÊÔÈË£ºÕÔС±ò * ÈÕÆÚ£º2013-09-2 ...

  9. GPS位置模拟-安卓

    测试定位功能时都需要位置模拟,一般有如下3种方式: a)手机上安装第三方模拟软件:需要Root: b)PC模拟其中运行app并模拟位置:不能在真机上运行,手机兼容性不能测试到: b)在app中让开发增 ...

  10. 守护进程daemon函数

    #include  <unistd.h> int daemon(int nochdir,int noclose) 在创建精灵进程的时候,往往需要将精灵进程的工作目录修改为"/&q ...