[BZOJ2002]HNOI2010弹飞绵羊|LCT

貌似有很多做法。。

LCT打的第一题就是这个,年代久远了。。

从后往前走的话这肯定是一颗树嘛。。查询就是查深度嘛。。修改就是断开一条边连到另一颗树上去嘛。。

以前的巨丑无比的代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
const int maxn=200005,MAX=999999999;
int c[maxn][3],pre[maxn],num[maxn],size[maxn],isroot[maxn],i,n,m,cc,a,b;
void update(int x) {size[x]=size[c[x][0]]+size[c[x][1]]+1;}
void rotate(int x,int kind)
{int y=pre[x],z=pre[y];
int t=size[x];
size[x]=size[y];
size[y]=size[y]-t+size[c[x][kind]];
pre[y]=x;
c[y][!kind]=c[x][kind];
pre[c[x][kind]]=y;
c[x][kind]=y;
pre[x]=z;
if (z&&!isroot[y]) c[z][c[z][1]==y]=x;
if (isroot[y])
	{isroot[y]=0;
	isroot[x]=1;
	}
}
void splay(int x)
{while (!isroot[x] )
	{if (isroot[pre[x]]) rotate(x,c[pre[x]][0]==x);
	else 
		{int y=pre[x],kind=c[pre[y]][0]==y;
			if (c[y][kind]!=x)
				{rotate(y,kind);
				rotate(x,kind);
				}
			else 
				{rotate(x,!kind);
				rotate(x,kind);
				}
		}
	}
}
void print(int x)
{if (x==0) return;
printf("/%d %d %d %d %d %d %d\n",x,num[x],size[x],pre[x],c[x][0],c[x][1],isroot[x]);
print(c[x][0]);
print(c[x][1]);
}
void access(int x)
{splay(x);
if (c[x][1]) isroot[c[x][1]]=1;
c[x][1]=0;
update(x);
int u;
while (pre[x])
	{u=pre[x];
	splay(u);
	if (c[u][1]) isroot[c[u][1]]=1;	
	c[u][1]=x;
	isroot[x]=0;
	update(u);
	update(x);
	splay(x);
	//print(x);
	}
//print(x);
}
void cut(int x)
{access(x);
splay(x);
if (c[x][0])
	{pre[c[x][0]]=pre[x];
	isroot[c[x][0]]=1;
	}
c[x][0]=0;
pre[x]=0;
update(x);
}
void join(int y,int x)
{if (y>n) y=n+1;
pre[x]=y;
access(x);
}
int main()
{freopen("sheep.in","r",stdin);
freopen("my.out","w",stdout);
scanf("%d",&n);
for (i=1;i<=n;i++)
	{scanf("%d",&num[i]);
//	cout<<"**";
	size[i]=1;
	pre[i]=i+num[i];
	c[i][0]=c[i][1]=0;
	isroot[i]=1;
	if (pre[i]>n) pre[i]=n+1;
	}
c[n+1][0]=c[n+1][1]=0;size[n+1]=1;isroot[n+1]=1;pre[n+1]=0;size[0]=0;
scanf("%d",&m);
for (i=1;i<=m;i++)
	{scanf("%d",&cc);
	if (cc==1)
		{scanf("%d",&a);
		access(a+1);
		splay(a+1);
		//print(a);
		printf("%d\n",size[a+1]-size[c[a+1][1]]-1);
		}
	else 
		{scanf("%d%d",&a,&b);
		if (b==num[a+1]) continue;
		num[a+1]=b;
		cut(a+1);
		join(a+1+num[a+1],a+1);
	//		for (int j=1;j<=n+1;j++)
	//	printf("/%d %d %d %d %d %d %d\n",j,num[j],size[j],pre[j],c[j][0],c[j][1],isroot[j]);
		}
	} 
fclose(stdin);
fclose(stdout);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值