联赛模拟18_联盟




没有用\(O(n)\)的做法,是\(O(nlogn)\)的线段树维护直径 (O(n)的需要维护的信息我觉得又多又乱)

将树的节点按\(dfs\)序建线段树维护联通块的直径

枚举每一条边,查看删掉它之后,剩余的两个联通块合并后的直径 所能取到的 最小的最大值

即 最小的 len=max {\(l_1\),\(l_2\),\(\frac{l_1+1}{2}\) + \(\frac{l_2+1}{2}\) +1}

\(l_1和l_2\) 是两个联通块的直径。

记录\(len\)的最小值及其个数,以及此时的要删的边的编号。

对于找端点,选一条要删的边,输出其端点,然后分别\(dfs\)找到两个联通块直径的中点输出即可

Code
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cctype>
using namespace std;
char buf[1<<20],*p1,*p2;
#define L (rt*2)
#define R (rt*2+1)
#define rint register int
#define gc() (p1==p2?(p2=buf+fread(p1=buf,1,1<<20,stdin),p1==p2?EOF:*p1++):*p1++)
#define read() ({\
	rint x=0;register bool f=0;register char ch=gc();\
	while(!isdigit(ch)) f|=ch=='-',ch=gc();\
	while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch&15),ch=gc();\
	f?-x:x;\
})
const int maxn=3e5+5;
int n;
int cnt;
int Time;
int head[maxn];
int dfn[maxn],ref[maxn];
int dep[maxn],fa[maxn],son[maxn],siz[maxn],top[maxn];
int Min=0x3f3f3f3f;
int mx[maxn][2];
int jilu[maxn];
int G,max_part;
int no_vis;

struct Seg{ int x,y; }t[maxn*4];
struct Edge{ int from,to,next; }e[maxn*2],ed[maxn];

void Aedge(int x,int y){
	e[++cnt].to=y;
	e[cnt].next=head[x];
	head[x]=cnt;
}
void dfs1(int x,int prt){
	siz[x]=1,fa[x]=prt,dep[x]=dep[prt]+1;
	for(int i=head[x];i;i=e[i].next){
		const rint y=e[i].to;
		if(y==prt) continue;
		dfs1(y,x);
		siz[x]+=siz[y];
		if(!son[x]||siz[son[x]]<siz[y]) son[x]=y;
	}
}
void dfs2(int x,int tp){
	top[x]=tp,dfn[x]=++Time,ref[Time]=x;
	if(son[x]) dfs2(son[x],tp);
	for(int i=head[x];i;i=e[i].next){
		const rint y=e[i].to;
		if(y!=son[x]&&y!=fa[x]) dfs2(y,y);
	}
}
int lca(int x,int y){
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		x=fa[top[x]];
	}
	return dep[x]<dep[y]?x:y;
}
int cal(int x,int y){
	return dep[x]+dep[y]-dep[lca(x,y)]*2;
}

int res[5],xx,yy,max_len;
Seg up(Seg A,Seg B){
	Seg ans;
	max_len=-1;
	res[1]=A.x,res[2]=A.y,res[3]=B.x,res[4]=B.y;
	for(int i=1;i<=4;++i){
		for(int j=i+1;j<=4;++j){
			const rint dis=cal(res[i],res[j]);
			if(dis>max_len){
				max_len=dis;
				xx=res[i];
				yy=res[j];
			}
		}
	}
	ans=(Seg){xx,yy};
	return ans;
}
void build(int rt,int l,int r){
	if(l==r) return t[rt].x=t[rt].y=ref[l],void();
	const int mid=(l+r)/2;
	build(L,l,mid),build(R,mid+1,r);
	t[rt]=up(t[L],t[R]);
}
Seg find(int rt,int l,int r,int x,int y){
	if(x==l&&r==y) return t[rt];
	int mid=(l+r)/2;
	if(y<=mid) return find(L,l,mid,x,y);
	if(x >mid) return find(R,mid+1,r,x,y);
	return up(find(L,l,mid,x,mid),find(R,mid+1,r,mid+1,y));
}

void dfs(int x,int prt){
	mx[x][0]=0,mx[x][1]=0;
	for(int i=head[x];i;i=e[i].next){
		const int y=e[i].to;
		if(y==prt||y==no_vis) continue;
		dfs(y,x);
		if(mx[y][0]+1>mx[x][0]) mx[x][1]=mx[x][0],mx[x][0]=mx[y][0]+1;
		else if(mx[y][0]+1>mx[x][1]) mx[x][1]=mx[y][0]+1;
	}
}
void find_G(int x,int prt,int dep){
	if(!G||max(mx[x][0],dep)<max_part) max_part=max(mx[x][0],dep),G=x;
	for(int i=head[x];i;i=e[i].next){
		int y=e[i].to;
		if(y==prt||y==no_vis) continue;
		int tmp;
		if(mx[x][0]==mx[y][0]+1) find_G(y,x,max(dep+1,mx[x][1]+1));
		else find_G(y,x,max(dep+1,mx[x][0]+1));
	}
}
int main(){
	freopen("league.in","r",stdin);
	freopen("league.out","w",stdout);
	n=read();
	for(int i=1;i<n;++i){
		Aedge(ed[i].from=read(),ed[i].to=read());
		Aedge(ed[i].to,ed[i].from);
	}
	dfs1(1,0);
	dfs2(1,1);
	build(1,1,n);
	for(int i=1;i<n;++i){
		int x=ed[i].from,y=ed[i].to;
		if(dep[x]>dep[y]) swap(x,y);

		Seg a2;
		if(dfn[y]+siz[y]<=Time) a2=up(find(1,1,n,1,dfn[y]-1),find(1,1,n,dfn[y]+siz[y],Time));
		else a2=find(1,1,n,1,dfn[y]-1);
		int len2=cal(a2.x,a2.y);
		if(len2>Min) continue;
	
		Seg a1=find(1,1,n,dfn[y],dfn[y]+siz[y]-1);
		int len1=cal(a1.x,a1.y);
		if(len1>Min) continue;

		int d=max(max(len1,len2),(len1+1)/2+(len2+1)/2+1);
		if(d<Min){
			Min=d;
			jilu[jilu[0]=1]=i;
		}
		else if(d==Min) jilu[++jilu[0]]=i;
	}
	printf("%d\n%d ",Min,jilu[0]);
	for(int i=1;i<=jilu[0];++i) printf("%d ",jilu[i]);
	printf("\n");

	int x=ed[jilu[1]].from,y=ed[jilu[1]].to;
	printf("%d %d ",x,y);
	no_vis=y;
	max_part=0x3f3f3f3f;
	dfs(x,0),find_G(x,0,0);
	printf("%d ",G);

	no_vis=x;
	max_part=0x3f3f3f3f;
	dfs(y,0),find_G(y,0,0);
	printf("%d\n",G);
	
	return 0;
}
posted @ 2020-10-17 14:45  liuzhaoxu  阅读(109)  评论(3编辑  收藏  举报