「雅礼集训 2017 Day5」远行

考虑先分析一下题目给的性质啊:

道路的修建会满足:每一时刻,都不存在 ((u,v)) 使得 ((u,v)) 之间能通过多种方式到达。

妥妥的一棵树啊。

通过每条道路都需要单位时间

这棵树的边权为(1)

她都想选择一个她能到达的最远的小镇作为终点,并且她在行走过程中是不会走回头路的

就是找一个最远点,让(dis(u,k))最长,在树上的话,我们知道这个点(k)是这颗树上直径的两端之一。
所以我们需要记录直径端点

小镇之间陆续建起了一些双向的道路

两颗子树连在一起了,我们要维护出合并之后的树的直径端点,有一个性质就是:这个两个端点一定是原两棵树的直径四个端点之二。
那么我们只要六种情况都试一下就好了。

那么我们需要做什么:
动态维护树上路径。
维护每一颗树的直径端点。

那么(LCT),(DSU)

「雅礼集训 2017 Day5」珠宝
#include<iostream>
#include<cstdio>
#define ll long long 
#define N 3000005

//___________________

ll f[N],c[N][2],siz[N],st[N];
bool ri[N];

#define l(x) c[x][0]
#define r(x) c[x][1]

inline bool nroot(int x){return l(f[x]) == x || r(f[x]) == x;}

inline void up(int x){siz[x] = (siz[l(x)] + siz[r(x)] + 1);}

inline void pushr(int x){std::swap(l(x),r(x));ri[x] ^= 1;}

inline void pushdown(int x){
	if(ri[x]){
		if(l(x))pushr(l(x));
		if(r(x))pushr(r(x));
		ri[x] = 0;
	} 
}

inline void rotate(int x){
	int y = f[x],z = f[y],k = r(y) == x,w = c[x][!k];
	if(nroot(y))
	c[z][r(z) == y] = x;c[x][!k] = y;c[y][k] = w;
	if(w)
	f[w] = y;f[y] = x;f[x] = z;
	up(y);up(x);
}

inline void splay(int x){
	ll y = x,z = 0;
	st[++z] = y;
	while(nroot(y))st[++z] = y = f[y];
	while(z)pushdown(st[z -- ]);
	while(nroot(x)){
		ll y = f[x],z = f[y];
		if(nroot(y))
		rotate((l(y) == x) ^ (l(z) == y) ? x : y);
		rotate(x);
	}
	up(x);
}

inline void access(int x){
	for(int y = 0;x;x = f[y = x])
	splay(x),r(x) = y,up(x);
}

inline void makeroot(int x){access(x),splay(x),pushr(x);}

inline void split(int x,int y){makeroot(x),access(y),splay(y);}

inline void link(int x,int y){makeroot(x);f[x] = y;}

//__________________LCT

ll fa[N],l[N],r[N];

inline ll find(int x){return (fa[x] == x) ? x : fa[x] = find(fa[x]);}

inline void merge(int x,int y){//x -> y
	ll ans = 0,ansl,ansr;
	fa[x] = y;
	split(l[x],r[x]);
	if(siz[r[x]] - 1 > ans)
	ans = siz[r[x]] - 1,ansl = l[x],ansr = r[x];

	split(l[y],r[x]);
	if(siz[r[x]] - 1 > ans)
	ans = siz[r[x]] - 1,ansl = l[y],ansr = r[x];
	
	split(l[x],r[y]);
	if(siz[r[y]] - 1 > ans)
	ans = siz[r[y]] - 1,ansl = l[x],ansr = r[y];

	split(l[y],r[y]);
	if(siz[r[y]] - 1 > ans)
	ans = siz[r[y]] - 1,ansl = l[y],ansr = r[y];	

	split(l[x],l[y]);
	if(siz[l[y]] - 1 > ans)
	ans = siz[l[y]] - 1,ansl = l[x],ansr = l[y];	

	split(r[x],r[y]);
	if(siz[r[y]] - 1 > ans)
	ans = siz[r[y]] - 1,ansl = r[x],ansr = r[y];			

	l[y] = ansl,r[y] = ansr;
	
//	std::cout<<x<<" "<<y<<" "<<l[y]<<" "<<r[y]<<std::endl;
}

//__________________DSU

ll n,q,type,last;

int main(){
	scanf("%lld",&type);
	scanf("%lld%lld",&n,&q);
	for(int i = 1;i <= n;++i)
	fa[i] = l[i] = r[i] = i;
	while(q -- ){
		ll opt,u,v;
		scanf("%lld",&opt);
		if(opt == 1){
			scanf("%lld%lld",&u,&v);
			u ^= type * last;
			v ^= type * last;
			link(u,v);
			merge(find(u),find(v));
		}else{
			scanf("%lld",&u);
			u ^= type * last;
			ll al = l[find(u)],ar = r[find(u)];
			ll ans = 0;
//			std::cout<<al<<" "<<ar<<std::endl;
			split(al,u);
			ans = std::max(ans,siz[u] - 1);
			split(ar,u);
			ans = std::max(ans,siz[u] - 1);
			std::cout<<(last = ans)<<std::endl;
		}
	}
}

原文地址:https://www.cnblogs.com/dixiao/p/14842864.html