BZOJ3133[Baltic2013]ballmachine
题目描述
https://www.lydsy.com/JudgeOnline/problem.php?id=3133
题解
还是分两个操作来说吧。
先看第一个操作,放球,可以发现,对于祖先节点和后代节点来说,后代节点没有放球,祖先节点就不能放,对于兄弟节点来说,子树编号小的没放满,编号大的就不能放,可以发现这是树的后序遍历。
用堆维护这个顺序,依次放就好了。
第二问更简单,就是找到最靠上的有球的祖先,把那个位置拿走就好了。
代码
#include<iostream> #include<cstdio> #include<queue> #include<algorithm> #include<vector> #define N 100009 using namespace std; int p[20][N],deep[N],n,dfn[N],tot,root,dp[N]; bool tag[N]; struct node{ int x; bool operator <(const node &b)const{ return dfn[x]>dfn[b.x]; } }; priority_queue<node>q; vector<int>vec[N]; inline int rd(){ int x=0;char c=getchar();bool f=0; while(!isdigit(c)){if(c=='-')f=1;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} return f?-x:x; } inline bool cmp(int a,int b){return dp[a]<dp[b];} void predfs(int u){ dp[u]=u; for(int i=0;i<vec[u].size();++i){ int v=vec[u][i];predfs(v); dp[u]=min(dp[u],dp[v]); } } void dfs(int u){ for(int i=1;(1<<i)<=deep[u];++i)p[i][u]=p[i-1][p[i-1][u]]; for(int i=0;i<vec[u].size();++i){ int v=vec[u][i];deep[v]=deep[u]+1;p[0][v]=u; dfs(v); } dfn[u]=++tot; } int main(){ n=rd();int qu=rd();int x,opt,fa; for(int i=1;i<=n;++i){fa=rd();if(!fa)root=i;vec[fa].push_back(i);} predfs(root); for(int i=1;i<=n;++i)sort(vec[i].begin(),vec[i].end(),cmp); dfs(root); for(int i=1;i<=n;++i)q.push(node{i}); while(qu--){ opt=rd();x=rd(); if(opt==1){ int id; for(int i=1;i<=x;++i){ id=q.top().x;q.pop(); tag[id]=1; } printf("%d\n",id); } else{ int now=x; for(int i=19;i>=0;--i)if(p[i][now]&&tag[p[i][now]])now=p[i][now]; tag[now]=0;q.push(node{now});printf("%d\n",deep[x]-deep[now]); } } return 0; }