bzoj2002

2002: [Hnoi2010]Bounce 弹飞绵羊

Time Limit: 10 Sec  Memory Limit: 259 MB
Submit: 3848  Solved: 2051
[Submit][Status]

Description

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

Input

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

Output

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

Sample Input


1 2 1 1
3
1 1
2 1 1
1 1

Sample Output

2
3


我的第一题LCT。现在仍理解得不是很透彻。

LCT:通过access操作把一棵树分解成若干条路径,用splay维护路径的信息,使复杂度达到logN级别

这题只有两个操作:
1.询问某节点的深点
2.修改某个节点的父亲

只用了access操作.

继续努力吧。LCT还要多写几题啊.

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>

using namespace std;

//fa[i],i如果不是splay的根,则表示i在splay中的父节点,否则表示i所splay表示的链连接的树中的父节点
//root[i],表示i是否是splay的根

struct tree{
	int ls,rs;
}tr[200011];

int fa[200011],size[200011];
bool root[200011];
int i,n,x,z,kind,m;

void update(int x)
{
	size[x]=size[tr[x].ls]+size[tr[x].rs]+1;
}

void right_rotate(int x)
{
	int y,z;
	y=tr[x].ls;
	z=tr[y].rs;
	tr[x].ls=z;
	tr[y].rs=x;
	fa[z]=x;
	if(tr[fa[x]].ls==x)tr[fa[x]].ls=y;
	if(tr[fa[x]].rs==x)tr[fa[x]].rs=y;
	fa[y]=fa[x];
	fa[x]=y;
	if(root[x]==true){
		root[y]=true;
		root[x]=false;
	}
	update(x);
	update(y);
}

void left_rotate(int x)
{
	int y,z;
	y=tr[x].rs;
	z=tr[y].ls;
	tr[x].rs=z;
	tr[y].ls=x;
	fa[z]=x;
	if(tr[fa[x]].ls==x)tr[fa[x]].ls=y;
	if(tr[fa[x]].rs==x)tr[fa[x]].rs=y;
	fa[y]=fa[x];
	fa[x]=y;
	if(root[x]==true){
		root[y]=true;
		root[x]=false;
	}
	update(x);
	update(y);
	
}

void splay(int x)
{
	while(root[x]==false){
		if(tr[fa[x]].rs==x)left_rotate(fa[x]);
		else right_rotate(fa[x]);
	}
}

void access(int x)
{
	int z;
	splay(x);
	while(fa[x]!=0){
		z=fa[x];
		splay(z);
		root[tr[z].rs]=true;
		root[x]=false;
		tr[z].rs=x;
		update(z);
		x=z;
		splay(x);
	}
}

int main()
{
	memset(root,true,sizeof(root));
	scanf("%d",&n);
	for(i=1;i<=n;i++){
		scanf("%d",&x);
		fa[i]=i+x;
		if(fa[i]>n)fa[i]=n+1;
	}
	for(i=1;i<=n+1;i++)size[i]=1;
	scanf("%d",&m);
	for(i=1;i<=m;i++){
		scanf("%d",&kind);
		if(kind==1){
			scanf("%d",&x);
			x++;
			access(x);
			splay(x);
			printf("%d\n",size[tr[x].ls]);
		}
		else{
			scanf("%d%d",&x,&z);
			x++;
			access(x);
			splay(x);
			fa[tr[x].ls]=fa[x];
			root[tr[x].ls]=true;
			tr[x].ls=0;
			size[x]=size[tr[x].rs]+1;
			fa[x]=x+z;
			if(fa[x]>n)fa[x]=n+1;
		}
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值