【BZOJ 3133】 3133: [Baltic2013]ballmachine (线段树+倍增)
3133: [Baltic2013]ballmachine
Time Limit: 20 Sec Memory Limit: 128 MB
Submit: 148 Solved: 66Description
有一个装球机器,构造可以看作是一棵树。有下面两种操作:
- 从根放入一个球,只要下方有空位,球会沿着树滚下。如果同时有多个点可以走,那么会选择编号最小的节点所在路径的方向。比如依次在树根
4
放2个球,第一个球会落到1
,第二个会落到3
:
- 从某个位置拿走一个球,那么它上方的球会落下来。比如依次拿走
5, 7, 8
三个球:Input
第一行:球的个数
N
,操作个数Q
(N, Q <= 100 000
)下面N
行:第i
个节点的父亲。如果是根,则为0
接下来Q
行:op num
op == 1
:在根放入num
个球op == 2
:拿走在位置num
的球Output
保证输入合法
op == 1
:输出最后一个球落到了哪里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求,这个我用倍增搞的。
就这样啊。不要看错题就好了啊。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #include<vector> 7 using namespace std; 8 #define Maxn 100010 9 10 int mymin(int x,int y) {return x<y?x:y;} 11 12 struct node 13 { 14 int x,y,next; 15 }t[Maxn*2]; 16 int first[Maxn],len; 17 18 void ins(int x,int y) 19 { 20 t[++len].x=x;t[len].y=y; 21 t[len].next=first[x];first[x]=len; 22 } 23 24 int dfn[Maxn],fn[Maxn],c[Maxn],fa[Maxn],dep[Maxn],mn[Maxn],cnt=0; 25 int ff[Maxn][20]; 26 bool p[Maxn]; 27 28 void dfs1(int x) 29 { 30 mn[x]=x; 31 for(int i=first[x];i;i=t[i].next) if(t[i].y!=fa[x]) 32 { 33 int y=t[i].y; 34 dfs1(y); 35 mn[x]=mymin(mn[x],mn[y]); 36 } 37 } 38 39 bool cmp(int x,int y) {return mn[x]<mn[y];} 40 41 int son[Maxn]; 42 void dfs(int x) 43 { 44 dep[x]=dep[fa[x]]+1; 45 int st=son[0],ed; 46 for(int i=first[x];i;i=t[i].next) if(t[i].y!=fa[x]) 47 { 48 int y=t[i].y; 49 son[++son[0]]=y; 50 }ed=son[0]; 51 sort(son+st+1,son+1+ed,cmp); 52 for(int i=st+1;i<=ed;i++) dfs(son[i]); 53 dfn[x]=++cnt; 54 fn[cnt]=x; 55 } 56 57 58 struct nnode 59 { 60 int l,r,lc,rc,sm; 61 }tr[Maxn*2]; 62 63 int tot=0; 64 int build(int l,int r) 65 { 66 int x=++tot; 67 tr[x].l=l;tr[x].r=r;tr[x].sm=0; 68 if(l!=r) 69 { 70 int mid=(l+r)>>1; 71 tr[x].lc=build(l,mid); 72 tr[x].rc=build(mid+1,r); 73 } 74 else tr[x].lc=tr[x].rc=0; 75 return x; 76 } 77 78 void change(int x,int y,int z) 79 { 80 if(tr[x].l==tr[x].r) 81 { 82 tr[x].sm=z; 83 return; 84 } 85 int mid=(tr[x].l+tr[x].r)>>1; 86 if(y<=mid) change(tr[x].lc,y,z); 87 else change(tr[x].rc,y,z); 88 tr[x].sm=tr[tr[x].lc].sm+tr[tr[x].rc].sm; 89 } 90 91 int query(int x) 92 { 93 if(tr[x].l==tr[x].r) return tr[x].l; 94 int lc=tr[x].lc,rc=tr[x].rc; 95 int mid=(tr[x].l+tr[x].r)>>1; 96 if(tr[lc].sm<mid-tr[x].l+1) return query(tr[x].lc); 97 return query(tr[x].rc); 98 } 99 100 int ffind(int x) 101 { 102 for(int j=18;j>=0;j--) if(ff[x][j]&&p[ff[x][j]]) 103 x=ff[x][j]; 104 return x; 105 } 106 107 int main() 108 { 109 int n,q; 110 scanf("%d%d",&n,&q); 111 len=0; 112 memset(first,0,sizeof(first)); 113 int rt=0; 114 for(int i=1;i<=n;i++) 115 { 116 int x; 117 scanf("%d",&x); 118 fa[i]=x; 119 if(x==0) rt=i; 120 else ins(x,i); 121 } 122 for(int i=1;i<=n;i++) ff[i][0]=fa[i]; 123 for(int i=1;i<=n;i++) p[i]=0; 124 for(int j=1;(1<<j)<=n;j++) 125 for(int i=1;i<=n;i++) 126 ff[i][j]=ff[ff[i][j-1]][j-1]; 127 dep[0]=0; 128 dfs1(rt); 129 son[0]=0;dfs(rt); 130 build(1,n); 131 for(int i=1;i<=q;i++) 132 { 133 int op,x; 134 scanf("%d%d",&op,&x); 135 if(op==1) 136 { 137 while(x--) 138 { 139 int y=query(1); 140 change(1,y,1); 141 p[fn[y]]=1; 142 if(x==0) printf("%d\n",fn[y]); 143 } 144 } 145 else 146 { 147 if(!p[x]) continue; 148 int y=ffind(x); 149 change(1,dfn[y],-1); 150 p[y]=0; 151 printf("%d\n",dep[x]-dep[y]); 152 } 153 } 154 return 0; 155 }
2017-03-26 20:30:43