【loj6038】「雅礼集训 2017 Day5」远行 树的直径+并查集+LCT

题目描述

给你 $n$ 个点,支持 $m$ 次操作,每次为以下两种:连一条边,保证连完后是一棵树/森林;询问一个点能到达的最远的点与该点的距离。强制在线。

$n\le 3\times 10^5$ ,$m\le 5\times 10^5$ 。


题解

树的直径+并查集+LCT

与直径相关的结论1:与一个点距离最大的点为任意一条直径的两个端点之一。

与直径相关的结论2:两棵树之间连一条边,新树直径的两个端点一定为第一棵树直径的两个端点和第二棵树直径的两个端点这四者中之二。

于是问题就变简单了,用并查集维护每个连通块的直径即可。由于强制在线,所以必须用LCT维护树上距离。

时间复杂度 $O(LCT·n\log n)=O(能过)$ 

#include <cstdio>
#include <algorithm>
#define N 300010
using namespace std;
int f[N] , px[N] , py[N] , fa[N] , c[2][N] , si[N] , rev[N];
int find(int x)
{
	return x == f[x] ? x : f[x] = find(f[x]);
}
inline void pushup(int x)
{
	si[x] = si[c[0][x]] + si[c[1][x]] + 1;
}
inline void pushdown(int x)
{
	if(rev[x])
	{
		swap(c[0][c[0][x]] , c[1][c[0][x]]) , rev[c[0][x]] ^= 1;
		swap(c[0][c[1][x]] , c[1][c[1][x]]) , rev[c[1][x]] ^= 1;
		rev[x] = 0;
	}
}
inline bool isroot(int x)
{
	return x != c[0][fa[x]] && x != c[1][fa[x]];
}
void update(int x)
{
	if(!isroot(x)) update(fa[x]);
	pushdown(x);
}
inline void rotate(int x)
{
	int y = fa[x] , z = fa[y] , l = (c[1][y] == x) , r = l ^ 1;
	if(!isroot(y)) c[c[1][z] == y][z] = x;
	fa[x] = z , fa[y] = x , fa[c[r][x]] = y , c[l][y] = c[r][x] , c[r][x] = y;
	pushup(y) , pushup(x);
}
inline void splay(int x)
{
	int y , z;
	update(x);
	while(!isroot(x))
	{
		y = fa[x] , z = fa[y];
		if(!isroot(y))
		{
			if((c[0][y] == x) ^ (c[0][z] == y)) rotate(x);
			else rotate(y);
		}
		rotate(x);
	}
}
inline void access(int x)
{
	int t = 0;
	while(x) splay(x) , c[1][x] = t , pushup(x) , t = x , x = fa[x];
}
inline void makeroot(int x)
{
	access(x) , splay(x) , swap(c[0][x] , c[1][x]) , rev[x] ^= 1;
}
inline int dis(int x , int y)
{
	makeroot(x) , access(y) , splay(y);
	return si[y];
}
inline void link(int x , int y)
{
	int tx = find(x) , ty = find(y) , mx = -1 , t , rx , ry;
	makeroot(x) , fa[x] = y;
	if(mx < (t = dis(px[tx] , py[tx]))) mx = t , rx = px[tx] , ry = py[tx];
	if(mx < (t = dis(px[ty] , py[ty]))) mx = t , rx = px[ty] , ry = py[ty];
	if(mx < (t = dis(px[tx] , px[ty]))) mx = t , rx = px[tx] , ry = px[ty];
	if(mx < (t = dis(px[tx] , py[ty]))) mx = t , rx = px[tx] , ry = py[ty];
	if(mx < (t = dis(py[tx] , px[ty]))) mx = t , rx = py[tx] , ry = px[ty];
	if(mx < (t = dis(py[tx] , py[ty]))) mx = t , rx = py[tx] , ry = py[ty];
	f[tx] = ty , px[ty] = rx , py[ty] = ry;
}
int main()
{
	int type , n , q , i , opt , x , y , ans = 0;
	scanf("%d%d%d" , &type , &n , &q);
	for(i = 1 ; i <= n ; i ++ ) f[i] = px[i] = py[i] = i , si[i] = 1;
	while(q -- )
	{
		scanf("%d%d" , &opt , &x) , x ^= ans;
		if(opt == 1) scanf("%d" , &y) , y ^= ans , link(x , y);
		else y = find(x) , printf("%d\n" , ans = max(dis(x , px[y]) , dis(x , py[y])) - 1);
		if(!type) ans = 0;
	}
	return 0;
}

 

posted @ 2018-03-22 15:20  GXZlegend  阅读(1040)  评论(0编辑  收藏  举报