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. 【BZOJ】1901: Zju2112 Dynamic Rankings

    [题意]带修改的查询区间第k小 [算法]树状数组套可持久化线段树 [题解]对于树状数组上的每个节点,维护可持久化权值线段树(节点为权值),从而达到查询前缀和的目的. 对于每次修改,在待修改线段树基础上 ...

  2. java对象与json互转

    package com.liveyc; import java.io.StringWriter; import org.junit.Test; import com.fasterxml.jackson ...

  3. low逼三人组、nb二人组、归并、希尔排序----小结

  4. 蓝色的oa模板html_综合信息服务管理平台OA模板——后台

    链接:http://pan.baidu.com/s/1qXGGOAK 密码:2otu

  5. (2)剑指Offer之二维数组查找和替换空格问题

    一 二维数组查找 题目描述: 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 问 ...

  6. 我的Apache又挂了之apache错误:server's fully qualified domain name, using 127.0.0.1. Set the 'ServerName'

    表示物理机装Apache然后有时候关机会忘了关闭Apache然后长此以往会导致各种Apache起不来的缘故,上一次已经出现过一次.今天又出现了 再次记录一下解决的方法. 1.查看错误日志 /var/l ...

  7. Linux CGI编程基础【整理】

    Linux CGI编程基础 1.为什么使用CGI? 如前面所见,任何的HTML均是静态网页,它无法实现一些复杂的功能,而CGI可以为我们实现.如:a.列出服务器上某个目录中的文件,对目录中的文件进行操 ...

  8. Git学习笔记3 git revert

    我们难免会因为种种原因执行一些错误的commit / push,git提供了revert命令帮助程序员修复这样的错误. 举个例子,下图是git commit 的历史记录 git revert 命令会通 ...

  9. Linux中等待队列的实现

    1.       等待队列数据结构 等待队列由双向链表实现,其元素包括指向进程描述符的指针.每个等待队列都有一个等待队列头(wait queue head),等待队列头是一个类型为wait_quequ ...

  10. caffe Python API 之Model训练

    # 训练设置 # 使用GPU caffe.set_device(gpu_id) # 若不设置,默认为0 caffe.set_mode_gpu() # 使用CPU caffe.set_mode_cpu( ...