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

3133: [Baltic2013]ballmachine

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

Description

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

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

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

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

上一篇:【Android】LMK 工作机制


下一篇:json数据交换