• BZOJ2002 [Hnoi2010]Bounce 弹飞绵羊 LCT


    欢迎访问~原文出处——博客园-zhouzhendong

    去博客园看该题解


    题目传送门 - BZOJ2002


    题意概括

      沿着一条直线有n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹ki步,达到第i+ki个装置,若不存在第i+ki个装置,则绵羊被弹飞。当它从第i个装置起步时,被弹几次后会被弹飞?此外,还会中途修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。


    题解

      几乎是LCT板子题。

      首先根据输入的建树。

      然后,如果是询问,那么先把n+1弄成根(rever),然后从询问的节点a向根打通一条路径(access),然后把a旋转到树根(splay),则size[ls[a]]就是答案。

      如果是修改,那么就是切掉一条边再连接一条边,这就是LCT(Link_Cut_Tree)的精髓:link和cut。


    代码

    #include <cstring>
    #include <cstdio>
    #include <cstdlib>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    const int N=200005;
    int n,m,Next[N];
    int fa[N],son[N][2],size[N],rev[N];
    void pushup(int x){
    	size[x]=size[son[x][0]]+size[son[x][1]]+1;
    }
    bool isroot(int x){
    	return son[fa[x]][0]!=x&&son[fa[x]][1]!=x;
    }
    void pushdown(int x){
    	if (rev[x]){
    		rev[x]=0;
    		rev[son[x][0]]^=1;
    		rev[son[x][1]]^=1;
    		swap(son[x][0],son[x][1]);
    	}
    }
    void pushadd(int x){
    	if (!isroot(x))
    		pushadd(fa[x]);
    	pushdown(x);
    }
    int wson(int x){
    	return son[fa[x]][1]==x;
    }
    void rotate(int x){
    	if (isroot(x))
    		return;
    	int y=fa[x],z=fa[y],L=son[y][1]==x,R=L^1;
    	if (!isroot(y))
    		son[z][wson(y)]=x;
    	fa[x]=z;
    	fa[y]=x;
    	fa[son[x][R]]=y;
    	son[y][L]=son[x][R];
    	son[x][R]=y;
    	pushup(y);
    	pushup(x);
    }
    void splay(int x){
    	pushadd(x);
    	for (int y=fa[x];!isroot(x);rotate(x),y=fa[x])
    		if (!isroot(y))
    			rotate((wson(x)^wson(y))?x:y);
    }
    void access(int x){
    	int t=0;
    	while (x){
    		splay(x);
    		son[x][1]=t;
    		t=x;
    		x=fa[x];
    	}
    }
    void rever(int x){
    	access(x);
    	splay(x);
    	rev[x]^=1;
    }
    void link(int x,int y){
    	rever(x);
    	fa[x]=y;
    }
    void cut(int x,int y){
    	rever(x);
    	access(y);
    	splay(y);
    	fa[x]=son[y][0]=0;
    }
    int main(){
    	scanf("%d",&n);
    	for (int i=1;i<=n;i++){
    		scanf("%d",&Next[i]);
    		fa[i]=Next[i]=min(i+Next[i],n+1);
    		size[i]=1;
    	}
    	size[n+1]=1;
    	memset(rev,0,sizeof rev);
    	scanf("%d",&m);
    	while (m--){
    		int op,a,b;
    		scanf("%d",&op);
    		if (op==1){
    			scanf("%d",&a),a++;
    			rever(n+1);
    			access(a);
    			splay(a);
    			printf("%d
    ",size[son[a][0]]);
    		}
    		else {
    			scanf("%d%d",&a,&b),a++;
    			cut(a,Next[a]);
    			link(a,Next[a]=min(a+b,n+1));
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    福建工程学院第十四届ACM校赛B题题解
    2018 ACM-ICPC青岛现场赛 B题 Kawa Exam 题解 ZOJ 4059
    联合周赛第二场 我在哪?题解
    维修数列 Splay(这可能是我写过最麻烦的题之一了。。。用平衡树维护dp。。。丧心病狂啊。。。。)
    虚树入门!世界树!
    御坂御坂题解(出自北航校赛) 约瑟夫环问题高效解决方案
    网络流24题! 开始!题解!
    AFO
    【模板库】减维的模板库【停更】
    【组合数学】Educational Codeforces Round 83 (Rated for Div. 2) D题
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/BZOJ2002.html
Copyright © 2020-2023  润新知