zoukankan      html  css  js  c++  java
  • [BZOJ 2002] [HNOI2010]弹飞绵羊(Link Cut Tree)

    题面

    某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹ki步,达到第i+ki个装置,若不存在第i+ki个装置,则绵羊被弹飞。绵羊想知道当它从第i个装置起步时,被弹几次后会被弹飞。为了使得游戏更有趣,Lostmonkey可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。

    分析

    首先把所有点编号+1,建立虚拟节点n+1表示被弹飞。如果i+ki>n就连边(i,n+1)否则连边(i,i+ki)。

    修改就是先删边再加边

    查询其实就是查询x到n+1的路径长度.split(x,n+1)后的子树大小-1即为答案

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm> 
    #define maxn 200000
    using namespace std;
    struct link_cut_tree{
    #define lson(x) (tree[x].ch[0])
    #define rson(x) (tree[x].ch[1])
    #define fa(x) (tree[x].fa)
    	struct node{
    		int ch[2];
    		int fa;
    		int sz;
    		int revm;
    	}tree[maxn+5];
    	inline bool is_root(int x){
    		return !(lson(fa(x))==x||rson(fa(x))==x);
    	}
    	inline int check(int x){
    		return rson(fa(x))==x;
    	}
    	void push_up(int x){
    		tree[x].sz=tree[lson(x)].sz+tree[rson(x)].sz+1;
    	}
    	void reverse(int x){
    		swap(lson(x),rson(x));
    		tree[x].revm^=1;
    	}
    	void push_down(int x){
    		if(tree[x].revm){
    			reverse(lson(x));
    			reverse(rson(x));
    			tree[x].revm=0;
    		}
    	}
    	void push_down_all(int x){
    		if(!is_root(x)) push_down_all(fa(x));
    		push_down(x);
    	}
    	void rotate(int x){
    		int y=fa(x),z=fa(y),k=check(x),w=tree[x].ch[k^1];
    		tree[y].ch[k]=w;
    		tree[w].fa=y;
    		if(!is_root(y)) tree[z].ch[check(y)]=x;
    		tree[x].fa=z;
    		tree[x].ch[k^1]=y;
    		tree[y].fa=x;
    		push_up(y);
    		push_up(x);
    	}
    	void splay(int x){
    		push_down_all(x);
    		while(!is_root(x)){
    			int y=fa(x);
    			if(!is_root(y)){
    				if(check(x)==check(y)) rotate(y);
    				else rotate(x);
    			}
    			rotate(x);
    		}
    		push_up(x);
    	}
    	void access(int x){
    		for(int y=0;x;y=x,x=fa(x)){
    			splay(x);
    			rson(x)=y;
    			push_up(x);
    		}
    	}
    	void make_root(int x){
    		access(x);
    		splay(x);
    		reverse(x);
    	}
    	void split(int x,int y){
    		make_root(x);
    		access(y);
    		splay(y);
    	}
    	void link(int x,int y){
    		make_root(x);
    		fa(x)=y;
    	}
    	void cut(int x,int y){
    		split(x,y);
    		lson(y)=fa(x)=0;
    		push_up(y);
    	}
    	int query(int x,int y){//查询x到y的路径长度,即split出来的子树大小-1 
    		split(x,y);
    		return tree[y].sz-1;
    	}
    }T;
    
    int n,m;
    int a[maxn+5];
    //虚拟节点n+1表示被弹飞 
    inline int get_nex(int x,int k){//找到被弹到的节点 
    	if(x+k<=n) return x+k;
    	else return n+1;
    }
    
    int main(){
    	int cmd,x,k;
    	scanf("%d",&n);
    	for(int i=1;i<=n+1;i++) T.tree[i].sz=1;
    //	T.link(4,5);
    	for(int i=1;i<=n;i++){
    		scanf("%d",&a[i]);
    		T.link(i,get_nex(i,a[i]));
    	}
    	scanf("%d",&m);
    	for(int i=1;i<=m;i++){
    		scanf("%d",&cmd);
    		if(cmd==1){
    			scanf("%d",&x);
    			x++;
    			printf("%d
    ",T.query(x,n+1));//查询x到n+1路径长度 
    		}else{
    			scanf("%d %d",&x,&k);
    			x++;
    			T.cut(x,get_nex(x,a[x]));
    			a[x]=k;
    			T.link(x,get_nex(x,a[x]));
    		}
    	}
    	 
    }
    
  • 相关阅读:
    jquery堆栈与队列
    类数组转成数组对象
    python基础教程总结8——特殊方法,属性,迭代器,生成器,八皇后问题
    python基础教程总结7——异常
    python基础教程总结6——类
    python基础教程总结5——函数
    python基础教程总结4—基本语句
    python——动态类型
    python基础教程总结3—字典
    python基础教程总结2——字符串
  • 原文地址:https://www.cnblogs.com/birchtree/p/11966280.html
Copyright © 2011-2022 走看看