Qtree V

摘要:
Lmnu表示距子画面子树的最上点最近的白点,其中u位于该点。rmnu表示距子画面子树的最低点最近的白点,其中u位于该点。打开一组,以保持与所有虚拟儿子都可以步行到的最近白点的距离。考虑俯卧撑。对于它的右儿子,考虑从这个点移动到它的虚拟儿子,或者通过它的左子树中深度最深的点。

lmn u 表示 u 所在splay子树最上方点距离最近的白点

rmn u 表示 u 所在splay子树最下方点距离最近的白点

开一个set维护所有虚儿子能走到的最近的白点的距离

考虑pushup,

对于它的右儿子,考虑要么从这个点走向它的虚儿子,要么通过它左子树中深度最大的点走。

对于它的左儿子要么从这个点走向它的虚儿子,要么通过它右子树的最浅点走。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<set>
using namespace std;
#define MAXN 100006
int n , m;
int ch[MAXN][2] , siz[MAXN] , fa[MAXN] , lmn[MAXN] , rmn[MAXN];
int w[MAXN];
multiset<int> S[MAXN];

bool notr( int u ) {
	return ( ch[fa[u]][0] == u ) || ( ch[fa[u]][1] == u );
}
void pushup( int u ) {
	int ls = ch[u][0] , rs = ch[u][1];
	siz[u] = siz[ls] + siz[rs] + 1;
	if( w[u] ) {
		lmn[u] = min( lmn[ls] , siz[ls] );
		rmn[u] = min( rmn[rs] , siz[rs] );
		return;
	}
	int t = S[u].empty() ? 0x3f3f3f3f : *S[u].begin();
	lmn[u] = min( lmn[ls] , lmn[rs] + siz[ls] + 1 );
	rmn[u] = min( rmn[rs] , rmn[ls] + siz[rs] + 1 );
	lmn[u] = min( lmn[u] , t + siz[ls] ) , rmn[u] = min( rmn[u] , t + siz[rs] );
}
void rotate( int x ) {
	int f = fa[x] , g = fa[f] , w = ch[fa[x]][1] == x;
	int wf = ch[g][1]==f , k = ch[x][w^1];
	if( notr(f) ) ch[g][wf] = x; ch[f][w] = k , ch[x][w^1] = f;
	fa[f] = x , fa[k] = f , fa[x] = g;
	pushup( f ) , pushup( x );
}
void splay( int x ) {
	int f , g;
	while( notr( x ) ) {
		f = fa[x] , g = fa[f];
		if( notr( f ) ) 
			rotate( (ch[f][0]==x)^(ch[g][0]==f) ? x : f );
		rotate( x );
	}
}
void access( int x ) {
	for( int p = 0 ; x ; ( p = x , x = fa[x] ) ) {
		splay( x );
		if( ch[x][1] ) S[x].insert( 1 + lmn[ch[x][1]] );
		if( p ) S[x].erase( S[x].find( 1 + lmn[p] ) );
		ch[x][1] = p , pushup( x );
	}
}

int head[MAXN] , nex[MAXN << 1] , to[MAXN << 1] , ecn;
void ade( int u , int v ) {
	nex[++ ecn] = head[u] , to[ecn] = v , head[u] = ecn;
}
void dfs( int u , int f ) {
	fa[u] = f;
	for( int i = head[u] ; i ; i = nex[i] ) {
		int v = to[i];
		if( v == f ) continue;
		dfs( v , u );
		S[u].insert( 1 + 0x3f3f3f3f );
	}
	
}

int main() {
	cin >> n;
	for( int i = 1 , u , v ; i < n ; ++ i ) {
		scanf("%d%d",&u,&v);
		ade( u , v ) , ade( v , u );
	}
	dfs( 1 , 0 );
	lmn[0] = rmn[0] = 0x3f3f3f3f;
	for( int i = 1 ; i <= n ; ++ i ) 
		lmn[i] = rmn[i] = 0x3f3f3f3f , siz[i] = 1;
	cin >> m;
	int opt , u;
	while( m-- ) {
		scanf("%d%d",&opt,&u);
//	cout << S[1].size() << endl;
		if( opt == 0 ) {
			access( u ) , splay( u );
			w[u] ^= 1;
			pushup( u );
		} else {
			access( u ) , splay( u );
			printf("%d
",rmn[u] > n ? -1 : rmn[u]);
		}
	}
}

免责声明:文章转载自《Qtree V》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Xcode插件管理GridView 使用DataKeyNames属性下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

P3391 文艺平衡树(Splay做法)

您需要写一种数据结构(可参考题目标题),来维护一个有序数列。 其中需要提供以下操作:翻转一个区间,例如原有序序列是 5 4 3 2 15 4 3 2 1,翻转区间是 [2,4][2,4] 的话,结果是 5 2 3 4 15 2 3 4 1。 #include<bits/stdc++.h> using namespace std; const i...

splay模板 指针版&amp;amp;splay被卡祭

普通平衡树板子 参考了大佬博客 访问空指针会出错,我用了一个nil代替他。(c++是谁设计的我还得把结构体定义在外面真难受) #include<bits/stdc++.h> using namespace std; typedef pair<int,int> pii; #define forg(i,x) for(int i=firs...

ZJOI 2019 划水记

作为一个极其蒟蒻的OIer,虽然没有省选资格但还是去见见世面。 ZJOI2019一试是在浙江省镇海中学。听名字就很霸气。 学习OI的最后一年,记录下一些事情,即使最终走到最后也一无所获,也是一段美好的记忆吧。 起码,我努力过。 ——ljc20020730 Day -1 20190323 晚上复习下基础数论,写了十几个板子(excrt,exgcd什么的),写...

Splay算法基础与习题

前言 Spaly是基于二叉查找树实现的, 什么是二叉查找树呢?就是一棵树呗:joy: ,但是这棵树满足性质—一个节点的左孩子一定比它小,右孩子一定比它大 比如说 这就是一棵最基本二叉查找树 对于每次插入,它的期望复杂度大约是logn级别的,但是存在极端情况,比如9999999 9999998 9999997.....1这种数据,会直接被卡成n2 在这种情...