【刷题】LOJ 6038 「雅礼集训 2017 Day5」远行

题目描述

Miranda 生活的城市有 (N) 个小镇,一开始小镇间没有任何道路连接。随着经济发现,小镇之间陆续建起了一些双向的道路但是由于经济不太发达,在建设过程中,会保证对于任意两个小镇,最多有一条路径能互相到达。有的时候 Miranda 会从某个小镇开始进行徒步旅行,每次出发前,她都想选择一个她能到达的最远的小镇作为终点,并且她在行走过程中是不会走回头路的,为了估算这次旅行的时间,她会需要你告诉她这次旅行的时间会是多少呢?可以假设通过每条道路都需要单位时间,并且 Miranda 不会在小镇停留。

输入格式

第一行一个整数 ( ext{type}),表示数据类型。

第二行两个整数 (N)(Q)

接下来 (Q) 行,每行先读入一个整数 (t) ,若 (t = 1) ,则接下来读入两个整数 (u)(v) ,表示小镇 (u) 与小镇 (v) 建立了一条新道路。若 (t = 2) ,读入一个整数 (u) ,表示 Miranda 要开始一次从小镇 (u) 出发的旅行。

  • ( ext{type} = 1) ,记 ( ext{lastAns}) 表示最近一次 Miranda 旅行的时间,那么对于每次操作的 (u)(u, v) ,都要异或上 ( ext{lastAns})

  • ( ext{type} = 0) ,则不需要对数据进行处理。

输出格式

对于每次询问,输出 Miranda 能到达的最远的小镇的距离是多少。注意 Miranda 可能只能留在开始的小镇。

样例

样例输入

0
5 10
1 4 5
2 3
2 5
2 1
1 5 3
1 1 4
2 3
2 5
1 5 2
2 1

样例输出

0
1
0
3
2
3

数据范围与提示

对于 (20\%) 的数据,(N leq 5000, Q leq 10000)

对于 (50\%) 的数据,(N leq 100000, Q leq 200000)

对于另外 (20\%) 的数据,( ext{type} = 0)

对于 (100\%) 的数据,(N leq 300000, Q leq 500000, ext{type} in { 0, 1 }) ,解密后的 (u)(v) 满足 (1 leq u, v leq N) ,且道路的修建会满足:每一时刻,都不存在 (u, v) 使得 (u, v) 之间能通过多种方式到达。

题解

直径的性质:

  1. 与一个点距离最大的点为任意一条直径的两个端点之一

  2. 两棵树之间连一条边,新树直径的两个端点一定为第一棵树直径的两个端点和第二棵树直径的两个端点这四者中之二

所以用LCT维护联通块直径的两个端点

查询时,把查询的点与两个端点分别split再询问size大小,取max即为答案

修改时,取出两个合并的联通块的直径的端点,四个,讨论6种情况,取距离最大的两个点为新的直径的端点

就这样就做完了

#include<bits/stdc++.h>
#define ui unsigned int
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
const int MAXN=300000+10;
int n,q,res,p1,p2,fa[MAXN],type,lastans;
std::pair<int,int> d[MAXN];
#define lc(x) ch[(x)][0]
#define rc(x) ch[(x)][1]
struct LinkCut_Tree{
	int size[MAXN],ch[MAXN][2],fa[MAXN],rev[MAXN],stack[MAXN],cnt;
	inline bool nroot(int x)
	{
		return lc(fa[x])==x||rc(fa[x])==x;
	}
	inline void reverse(int x)
	{
		std::swap(lc(x),rc(x));
		rev[x]^=1;
	}
	inline void pushup(int x)
	{
		size[x]=size[lc(x)]+size[rc(x)]+1;
	}
	inline void pushdown(int x)
	{
		if(rev[x])
		{
			if(lc(x))reverse(lc(x));
			if(rc(x))reverse(rc(x));
			rev[x]=0;
		}
	}
	inline void rotate(int x)
	{
		int f=fa[x],p=fa[f],c=(rc(f)==x);
		if(nroot(f))ch[p][rc(p)==f]=x;
		fa[ch[f][c]=ch[x][c^1]]=f;
		fa[ch[x][c^1]=f]=x;
		fa[x]=p;
		pushup(f);
		pushup(x);
	}
	inline void splay(int x)
	{
		cnt=0;
		stack[++cnt]=x;
		for(register int i=x;nroot(i);i=fa[i])stack[++cnt]=fa[i];
		while(cnt)pushdown(stack[cnt--]);
		for(register int y=fa[x];nroot(x);rotate(x),y=fa[x])
			if(nroot(y))rotate((lc(fa[y])==y)==(lc(y)==x)?y:x);
		pushup(x);
	}
	inline void access(int x)
	{
		for(register int y=0;x;x=fa[y=x])splay(x),rc(x)=y,pushup(x);
	}
	inline void makeroot(int x)
	{
		access(x);splay(x);reverse(x);
	}
	inline void split(int x,int y)
	{
		makeroot(x);access(y);splay(y);
	}
	inline void link(int x,int y)
	{
		makeroot(x);fa[x]=y;pushup(y);
	}
};
LinkCut_Tree T;
#undef lc
#undef rc
template<typename T> inline void read(T &x)
{
	T data=0,w=1;
	char ch=0;
	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
	if(ch=='-')w=-1,ch=getchar();
	while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
	x=data*w;
}
template<typename T> inline void write(T x,char ch='')
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)write(x/10);
	putchar(x%10+'0');
	if(ch!='')putchar(ch);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
inline int found(int x)
{
	if(fa[x]!=x)fa[x]=found(fa[x]);
	return fa[x];
}
inline void length(int x,int y)
{
	T.split(x,y);
	if(T.size[y]>res)res=T.size[y],p1=x,p2=y;
}
#define ft first
#define sd second
inline void modify(int x,int y)
{
	std::pair<int,int> a=d[found(x)],b=d[found(y)];
	res=0;T.link(x,y);
	length(a.ft,a.sd);length(a.ft,b.ft);length(a.ft,b.sd);
	length(a.sd,b.ft);length(a.sd,b.sd);length(b.ft,b.sd);
	d[found(y)]=std::make_pair(p1,p2);
	fa[found(x)]=found(y);
}
#undef ft
#undef sd
int main()
{
	read(type);
	read(n);read(q);
	for(register int i=1;i<=n;++i)fa[i]=i,d[i]=std::make_pair(i,i);
	while(q--)
	{
		int opt;read(opt);
		if(opt==1)
		{
			int u,v;read(u);read(v);
			if(type)u^=lastans,v^=lastans;
			modify(u,v);
		}
		if(opt==2)
		{
			int u,ans=0;read(u);
			if(type)u^=lastans;
			std::pair<int,int> now=d[found(u)];
			T.split(now.first,u);chkmax(ans,T.size[u]);
			T.split(now.second,u);chkmax(ans,T.size[u]);
			write(lastans=ans-1,'
');
		}
	}
	return 0;
}

原文地址:https://www.cnblogs.com/hongyj/p/9260455.html