【bzoj2002】 Hnoi2010—Bounce 弹飞绵羊

http://www.lydsy.com/JudgeOnline/problem.php?id=2002 (题目链接)

题意

  数轴上${n}$个点,每个点有一个权值${a_i}$,如果到达这个点,接下来会到达第${i+a_i}$个点。2个操作,修改某个权值,查询从一个点出发要经过多少点才能离开序列。

Solution

  lct的很多细节还是没有很明白啊。

  对于cut,如果我们知道cut的是x与x的祖先,那么就没有必要换根了。

  对于link,我们读入边的时候,其实想知道的只是每个点的父亲是谁。如果是无向边,必须link,因为你不知道读入的两个点的关系,而有向边的话就可以直接对fa数组赋值了。

细节

  好像没什么。。

代码

// bzoj2002
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#define LL long long
#define inf 2147483647
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;

const int maxn=200010;
int size[maxn],tr[maxn][2],fa[maxn];
int n,m;

void pushup(int x) {
	size[x]=size[tr[x][0]]+size[tr[x][1]]+1;
}
void rotate(int x) {
	int y=fa[x],z=fa[y],l,r;
	l=tr[y][1]==x;r=l^1;
	if (tr[z][0]==y || tr[z][1]==y) tr[z][tr[z][1]==y]=x;
	fa[x]=z;fa[y]=x;fa[tr[x][r]]=y;
	tr[y][l]=tr[x][r];tr[x][r]=y;
	pushup(y);pushup(x);
}
void splay(int x) {
	while (tr[fa[x]][0]==x || tr[fa[x]][1]==x) {
		int y=fa[x],z=fa[y];
		if (tr[z][0]==y || tr[z][1]==y) {
			if (tr[z][0]==y ^ tr[y][0]==x) rotate(x);
			else rotate(y);
		}
		rotate(x);
	}
}
void access(int x) {
	for (int y=0;x;y=x,x=fa[x])
		splay(x),tr[x][1]=y,pushup(x);
}
void link(int x,int y) {
	access(x);splay(x);
	tr[x][0]=fa[tr[x][0]]=0;pushup(x);
	fa[x]=y;
}
int main() {
	scanf("%d",&n);
	for (int x,i=1;i<=n;i++) {
		scanf("%d",&x);
		fa[i]=min(n+1,i+x);
	}
	scanf("%d",&m);
	for (int op,x,k,i=1;i<=m;i++) {
		scanf("%d%d",&op,&x);x++;
		if (op==1) {
			access(x);splay(x);printf("%d
",size[x]-1);
		}
		if (op==2) {
			scanf("%d",&k);
			link(x,min(n+1,x+k));
		}
	}
	return 0;
}
		
原文地址:https://www.cnblogs.com/MashiroSky/p/6377358.html