【BZOJ 2002】 [Hnoi2010]Bounce 弹飞绵羊 LCT

来源:互联网 发布:软件测试的目的 编辑:程序博客网 时间:2024/04/26 02:09

感觉LCT实在是太好玩了qwq。。。。。
这里我们首先思考没有改变操作该怎么做?可以把每一个节点和他将要到达的点(作为父亲节点)连边(建立一个虚拟的根节点表示弹飞绵羊),然后我们就得到了一棵树,每一个点需要弹射几次能够被弹飞就是他的深度-1咯(根节点深度为1)。但是如果有修改操作的话,说明树是动态的,LCT解决动态树,不会LCT的去切BZOJ 2049

说一下这里的link和cut操作,首先cut操作,首先我们access(a)这样由于i和fa[i]是相邻的而且fa[a]的深度更小,所以splay(a)以后,fa[a]就是a的左儿子了,切断以后更新一下就好了。

然后是link操作。现在link(a,b) (b是新的a的父亲节点),所以总的根节点一定是在b所在的树内对吧,也就是说是将a连入b,而在a这棵辅助树里,a的深度一定是最小的对吧(刚刚才cut出来的),所以他就是暂时原树的根节点咯,所以直接splay以后fa[a]=b就好了。

#include<cstdio>#include<cstring>#include<iostream>#define maxn 200020#define ls(u) ch[u][0]#define rs(u) ch[u][1]using namespace std;int n,m,k[maxn],fa[maxn],ch[maxn][2],size[maxn],rt;inline int Q(int u){return u==rs(fa[u]);}inline bool isrt(int u){return !fa[u]||(u!=ls(fa[u])&&u!=rs(fa[u]));}inline void push_up(int u){size[u]=size[ls(u)]+size[rs(u)]+1;}void rotate(int u){if(!u)return;int f=fa[u],ff=fa[f],d=!Q(u);if(!isrt(f))ch[ff][Q(f)]=u;fa[u]=ff;if(ch[u][d])fa[ch[u][d]]=f;ch[f][!d]=ch[u][d];ch[u][d]=f;fa[f]=u;push_up(f),push_up(u);} void splay(int u){if(!u)return;while(!isrt(u)){int f=fa[u];if(!isrt(f)){if(Q(u)==Q(f))rotate(f);else rotate(u);}rotate(u);}}void access(int u){for(int x=0;u;u=fa[x=u]){splay(u);rs(u)=x;push_up(u);}}void cut(int a){access(a),splay(a);fa[ls(a)]=0,ls(a)=0;push_up(a);}void link(int a,int b){access(a),splay(a);fa[a]=b;}int main(){scanf("%d",&n);rt=n+1;for(int i=1;i<=n;i++){scanf("%d",k+i);if(i+k[i]<=n)fa[i]=i+k[i];else fa[i]=rt;}scanf("%d",&m);int pos,a,b;while(m--){scanf("%d",&pos);if(pos==1){scanf("%d",&a);a++;access(a),splay(a);printf("%d\n",size[ls(a)]);}else {scanf("%d%d",&a,&b);a++;a+b>n?b=rt:b=a+b;cut(a),link(a,b);}}return 0;}


0 0
原创粉丝点击