zoukankan      html  css  js  c++  java
  • [Link-Cut-Tree][BZOJ2002]弹飞绵羊

    题面

    Description

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

    Input

    第一行包含一个整数(n),表示地上有(n)个装置,装置的编号从(0)(n-1)
    接下来一行有(n)个正整数,依次为那(n)个装置的初始弹力系数。
    第三行有一个正整数(m)
    接下来(m)行每行至少有两个数(i,j),若(i=1),你要输出从(j)出发被弹几次后被弹飞,若(i=2)则还会再输入一个正整数(k),表示第(j)个弹力装置的系数被修改成(k)

    Output

    对于每个(i=1)的情况,你都要输出一个需要的步数,占一行。

    Sample Input

    4
    1 2 1 1
    3
    1 1
    2 1 1
    1 1

    Sample Output

    2
    3

    Hint

    对于20%的数据(n,mle 10000);
    对于100%的数据(nle 200000,mle 100000);


    1.如何建树?

    • 若从这个点(x)会被弹飞,连边((x,n+1))
    • 若从这个点(x)不会被弹飞,连边((x,x+k_x))

    根为( extbf{n+1})

    以样例做例子:

    2.如何询问?

    哈?
    由于splay是按深度关键字排序,所以根的左子树的大小就是要被弹几次了呀。

    3.如何修改?

    把原来的边删了在连新的不就完了吗……


    代码

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int ch[200002][2],fa[200002],siz[200002],num[200002],lazr[200002],cnt,n,q;
    inline unsigned rd(){
    	unsigned re=0;
    	char ch=getchar();
    	while(ch<'0'||ch>'9')ch=getchar();
    	while(ch>='0'&&ch<='9'){
    		re=re*10+ch-'0';
    		ch=getchar();
    	}
    	return re;
    }
    inline bool isroot(int bt){return ch[fa[bt]][0]!=bt&&ch[fa[bt]][1]!=bt;}
    inline int drct(int bt){return ch[fa[bt]][1]==bt;}
    inline void pushup(int bt){siz[bt]=siz[ch[bt][0]]+siz[ch[bt][1]]+1;}
    inline void reverse(int bt){swap(ch[bt][0],ch[bt][1]);lazr[bt]^=1;}
    inline void pd(int bt){
    	if(lazr[bt]){
    		if(ch[bt][0])reverse(ch[bt][0]);
    		if(ch[bt][1])reverse(ch[bt][1]);
    		lazr[bt]=0;
    	}
    }
    inline void pushdown(int u){
    	if(!isroot(u))pushdown(fa[u]);
    	pd(u);
    }
    inline void rotate(int u){
    	int f=fa[u],g=fa[f],c=drct(u);
    	if(!isroot(f))ch[g][drct(f)]=u;
    	fa[u]=g;
    	ch[f][c]=ch[u][c^1];
    	if(ch[f][c])fa[ch[f][c]]=f;
    	ch[u][c^1]=f;
    	fa[f]=u;
    	pushup(f);
    	pushup(u);
    }
    void splay(int u){
    	pushdown(u);
    	while(!isroot(u)){
    		if(!isroot(fa[u]))rotate(drct(fa[u])==drct(u)?fa[u]:u);
    		rotate(u);
    	}
    }
    void access(int u){
    	for(int v=0;u;v=u,u=fa[u]){
    		splay(u);
    		ch[u][1]=v;
    		pushup(u);
    	}
    }
    void makeroot(int u){
    	access(u);
    	splay(u);
    	reverse(u);
    }
    void link(int a,int b){
    	makeroot(a);
    	fa[a]=b;
    }
    void cut(int a,int b){
    	makeroot(a);
    	access(b);
    	splay(b);
    	ch[b][0]=0;
    	fa[a]=0;
    	pushup(b);
    }
    int main(){
    	n=rd();
    	for(int i=1;i<=n;i++){
    		num[i]=rd();
    		siz[i]=1;
    	}
    	for(int i=1;i<=n;i++){
    		if(i+num[i]<=n)fa[i]=i+num[i];
    		else fa[i]=n+1;
    	}
    	q=rd();
    	for(int i=1;i<=q;i++){
    		int opt=rd(),x=rd()+1;
    		if(opt==1){
    			makeroot(n+1);
    			access(x);
    			splay(x);
    			printf("%d
    ",siz[ch[x][0]]);
    		}else{
    			int y=rd();
    			if(x+num[x]<=n)cut(x,x+num[x]);
    			else cut(x,n+1);
    			num[x]=y;
    			if(x+num[x]<=n)link(x,x+num[x]);
    			else link(x,n+1);
    		}
    	}
    }
    
  • 相关阅读:
    1
    iulg
    实验10
    作业5 指针应用
    作业4 函数应用
    实验9 指针
    实验 8 数组2
    实验7
    实验6 数组1
    实验5
  • 原文地址:https://www.cnblogs.com/eztjy/p/9382945.html
Copyright © 2011-2022 走看看