首页 > 其他分享 >2022杭电多校第十场1008 Minimum Diameter(树的直径的一些性质)

2022杭电多校第十场1008 Minimum Diameter(树的直径的一些性质)

时间:2022-08-21 19:56:33浏览次数:72  
标签:Diameter 杭电多校 fx len Minimum ans 直径 Map mx

解决本题分为两个部分:维护树的直径,合并多个树的直径

树的直径有如下性质:
1,从任一点出发,到达最远的点是直径的其中一端,从这一点出发可以到达最远的点是直径的另一端。或者说一棵树中距离某一点最远的点一定是直径的一端。
2,由1,两个树通过一条边连接形成的新的树的直径是两棵树直径4个端点的两两组合之一。

所以对于维护树的直径,可以维护每一棵树直径的两个端点,合并时用\(LCT\)的\(split\)或者离线+\(LCA\)暴力判断。

合并多棵树的直径时,合并后的直径有3种可能:
1.直径最长的树的直径
2.直径最长和次长树合并后直径
3.直径次长和第3场树合并在直径最长的树上后点的直径

用堆维护每一棵树的直径然后判断即可。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
#define N 101000
priority_queue<int> q;
int sum[N],fa[N],ch[N][2],val[N],rev[N],stack[N];
int read(){
	int sum=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
	return sum*f;
}
void update(int now){
	sum[now]=sum[ch[now][0]]+sum[ch[now][1]]+val[now];
}
bool son(int now){
	return ch[fa[now]][1]==now;
}
bool isroot(int now){
	return ch[fa[now]][0]!=now&&ch[fa[now]][1]!=now;
}
void rotate(int x){
	int y=fa[x],z=fa[y],a=son(x),b=son(y),s=ch[x][!a];
	if(!isroot(y))ch[z][b]=x;fa[x]=z;
	if(s)fa[s]=y;ch[y][a]=s;
	fa[y]=x;ch[x][!a]=y;
	update(y),update(x);
} 
void rever(int now){
	swap(ch[now][0],ch[now][1]);
	rev[now]^=1;
}
void pushdown(int now){
	if(rev[now]==0)return;
	if(ch[now][0])rever(ch[now][0]);
	if(ch[now][1])rever(ch[now][1]);
	rev[now]=0;
}
void splay(int x){
	int now=x,top=0;
	while(!isroot(now))stack[++top]=now,now=fa[now];
	stack[++top]=now;
	while(top)pushdown(stack[top--]);
	while(!isroot(x)){
		int y=fa[x];
		if(isroot(y))rotate(x);
		else{
			rotate(son(x)==son(y)?y:x);
			rotate(x);
		}
	}
}
void access(int now){
	for(int x=now,y=0;x;y=x,x=fa[x])
		splay(x),ch[x][1]=y,update(x);
}
void makeroot(int now){//相当于now与root路径上的点收尾交换,对应虚儿子也跟随变动。 
	access(now);
	splay(now);
	rever(now);
}
int findroot(int now){
	access(now);
	splay(now);
	while(ch[now][0])pushdown(now),now=ch[now][0];
	return now;
}
void split(int x,int y){
	makeroot(x);
	access(y);
	splay(y);
}
void link(int x,int y){
	makeroot(x);
	if(findroot(y)!=x)fa[x]=y;
}
int f[N],mx[N][2],len[N],Map[N];
int find(int x){
	if(f[x]==x)return x;
	else return f[x]=find(f[x]);
}
int main(){
	int T=read();
	while(T--){
		int n=read(),m=read();
		for(int i=1;i<=n;i++)val[i]=sum[i]=1,q.push(1);
		for(int i=1;i<=n;i++){
			f[i]=i;
			mx[i][0]=mx[i][1]=i;
			len[i]=1;
		} 
		while(m--){
			int x=read(),y=read();
			link(x,y);
			int fx=find(x),fy=find(y);
			Map[len[fx]]++;Map[len[fy]]++;
			int mx_len=0;
			int ans_a,ans_b;
			if(len[fx]>len[fy]){
				ans_a=mx[fx][0],ans_b=mx[fx][1];
				mx_len=len[fx];
			}
			else{
				ans_a=mx[fy][0],ans_b=mx[fy][1];
				mx_len=len[fy];	
			}
			for(int i=0;i<=1;i++)
				for(int j=0;j<=1;j++){
					int a=mx[fx][i],b=mx[fy][j];
					split(a,b);
					if(sum[b]>mx_len){
						ans_a=a,ans_b=b;
						mx_len=sum[b];
					}
				}
			f[fy]=fx;
			mx[fx][0]=ans_a,mx[fx][1]=ans_b; 
			len[fx]=mx_len;
			q.push(len[fx]);
			int len_a=-1,len_b=-1,len_c=-1;
			while(!q.empty()){
				len_a=q.top();
				q.pop();
				if(Map[len_a]==0)break;
				else Map[len_a]--,len_a=-1; 
			}
			while(!q.empty()){
				len_b=q.top();
				q.pop();
				if(Map[len_b]==0)break;
				else Map[len_b]--,len_b=-1; 
			}
			while(!q.empty()){
				len_c=q.top();
				q.pop();
				if(Map[len_c]==0)break;
				else Map[len_c]--,len_c=-1; 
			}
			if(len_b==-1&&len_c==-1)printf("%d\n",len_a-1);
			else if(len_c==-1)printf("%d\n",max(len_a-1,len_a/2+len_b/2+1));
			else printf("%d\n",max(len_a-1,max(len_a/2+len_b/2+1,len_b/2+len_c/2+2))); 
			q.push(len_a);
			if(len_b!=-1)q.push(len_b);
			if(len_c!=-1)q.push(len_c);
		}
		while(!q.empty()){
			Map[q.top()]=0;
			q.pop();
		}
		for(int i=1;i<=n;i++)fa[i]=0,sum[i]=0,val[i]=0,ch[i][0]=ch[i][1]=0,rev[i]=0;
	}
	return 0;
} 

标签:Diameter,杭电多校,fx,len,Minimum,ans,直径,Map,mx
From: https://www.cnblogs.com/Xu-daxia/p/16610664.html

相关文章

  • 2022杭电多校第2~10场集(赛后补题)
    打完十场回顾一下之前一些的题都是简单题难的我不会继续努力  Luxurycruiseship纯签到完全背包。数据有点大。三个物品价值是互质的,我们把7,31,365乘起来,用n%(7*31......
  • 2022杭电多校第十场7、3、9、4
    1007EvenTreeSplit先考虑最简单的情况,如下图的边\((3,4)\),我们把这条边切掉,最后会留下一部分的点数为2,另一部分的点数依然是偶数。进一步思考可以知道,对于边\((u,v)\)......
  • 871. Minimum Number of Refueling Stops
    Acartravelsfromastartingpositiontoadestinationwhichis target mileseastofthestartingposition.Therearegasstationsalongtheway.Thegasst......
  • CF1092E. Minimal Diameter Forest
    \(\texttt{Difficulty:2000}\)题意给定\(n(1\len\le1000)\)个点,\(m(0\lem\len-1)\)条边组成的森林,现在增加一些边,是森林成为一棵树,并且其直径最小,求最小直径以及......
  • 【2022杭电多校】第九场 1008 Shortest Path in GCD Graph 【容斥+优化】
    链接https://acm.hdu.edu.cn/showproblem.php?pid=7240题意是有n个点组成的完全图,每个点的权重组成了1-n的排列,点i和点j的距离为\(gcd(i,j)\),给出q组询问,每次询问给出u......
  • 2022杭电多校第八场1、7、5
    1001Theramore观察以下两种情况:以0为例,上图就是说,只要有两个连续的0,我们就可以一直把它们往前移动直到移动到首位。同理只要有两个连续的1我们就可以把它们移动到尾部......
  • 杭电多校杂题收录
    前言和学长学弟一起打的hdu多校,打的很菜没啥难题收录,因为难的我都不会做。正题hdu7152-Copy题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=7152题目大意\(n......
  • 2022 杭电多校第八场 Vale of Eternal 凸包+找规律
    主要是存个代码,还有我踩的坑。。cin和cout真的很慢,很慢,非常慢..还有就是先把凸包求出来了,然后才能考虑凸包面积啥的刚开始思路错了,直接上多边形面积明明输出和标程都一......