[HNOI2010]弹飞绵羊

LCT的板子题

蒟蒻看到很多大佬用分块的方法解决了这道题,但是本蒟蒻不会分块,但我会LCT啊,所以就用LCT解决了这道题。

神奇的思路

对于每一个节点 维护他的size,每一个弹射器 由它即将到达的弹射器向他连边

虚拟一个n+1号节点 进行最后一次弹射,
每次直接查询对应位置的size即可。

也就是

把给出的数据当做森林,即i的父亲是i+k[i],询问的是到根的路径长度+1,可以修改父亲。所以只需要link操作即可,注意把超过n的节点设为0。每次询问先access,然后Splay到根(Splay中要维护size),这样所询问的答案就是节点在Splay上的左子树大小+1。

CODE:

// luogu-judger-enable-o2
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<algorithm>

using namespace std;

const int maxn = 200010;

inline int read(){
	int x = 0;
	int flag = true;
	int k = getchar();
	while(k != '-' && !isdigit(k))
	    k = getchar();
	if(k == '-'){
	   k = getchar();
	   flag = false;
	}
	while(isdigit(k)){
		x = x * 10 + k - '0';
		k = getchar();
	}
	return (flag ? x : -x);
}

struct node{
	int father;
	int ch[2];
	int size;
	bool is_root;
}tree[maxn];

int n,m,k[maxn];

void update(int x){
	tree[x].size=1;
	if(tree[x].ch[0]) tree[x].size += tree[tree[x].ch[0]].size;
	if(tree[x].ch[1]) tree[x].size += tree[tree[x].ch[1]].size;
}
inline int getson(int x){
	return x == tree[tree[x].father].ch[1];
}
void rotate(int x){
	if(tree[x].is_root) return;
	int k = getson(x),fa = tree[x].father;
	int fafa = tree[fa].father;
	tree[fa].ch[k] = tree[x].ch[k^1];
	if(tree[x].ch[k^1])
		tree[tree[x].ch[k^1]].father = fa;
	tree[x].ch[k^1] = fa;
	tree[fa].father = x;
	tree[x].father = fafa;
	if(!tree[fa].is_root)
		tree[fafa].ch[fa == tree[fafa].ch[1]] = x;
	else {
		tree[x].is_root = true;
		tree[fa].is_root = false;
	}
	update(fa);
	update(x);
}
void Splay(int x){
	for(int y ; !tree[x].is_root;rotate(x)){
		if(!tree[y = tree[x].father].is_root){
			rotate((getson(x) == getson(y)) ? y : x);
		}
	}
}
void access(int x){
	int y = 0;
	while(x){
		Splay(x);
		tree[tree[x].ch[1]].is_root = true;
		tree[tree[x].ch[1] = y].is_root = false;
		update(x);
		x = tree[y = x].father;
	}
}
void link(int u,int v){
	if(v > n) v = 0;
	access(u);
	Splay(u);
	tree[tree[u].ch[0]].is_root = true;
	tree[tree[u].ch[0]].father = 0;
	tree[u].ch[0] = 0;
	tree[u].father = v;
	update(u);
}
int Query(int x){
	access(x);
	Splay(x);
	return tree[tree[x].ch[0]].size + 1;
}

int main(){
	n = read();
	for(int i = 1 ; i <= n ; i++){
		tree[i].is_root = 1;
		tree[i].size = 1;
		tree[i].father = 0;
		tree[i].ch[0] = 0;
		tree[i].ch[1] = 0;
	}
	for(int i = 1 ; i <= n ; i++){
		k[i] = read();
		link(i,i + k[i]);
	}
	m = read();
	int xx,x,y;
	while(m--){
		xx = read();
		x = read();
		if(xx == 1)
			printf("%d
",Query(x+1));
		else if(xx == 2){
			y = read();
			link(x + 1,x + y + 1);
		}
	}
	return 0;
}

另外,LCT的时间复杂度是(O(logn^2)),所以不开氧气优化也能过。
蒟蒻的耗时为652ms。

原文地址:https://www.cnblogs.com/Repulser/p/9600779.html