codeforces1294F 2100分构造

题目传送门

题意:

一棵n个点的树,让你在上面找两两不同的三个点。

这三个点之间的简单路径会形成一个边集。使这个边集尽可能大。

输出边集的大小和这三个点。

数据范围:\dpi{150}1\leqslant n \leqslant 2\cdot 10^5 。

题解:

找出这棵树的直径,直径的两个端点是q和w。

q和w一定是这3个点中的2个。

第3个点是距离直径最远的点。如果找不到直径外的第3个点,那第3个点就在直径上。

感受:

不知道为什么,这么显然没想出来。

刚睡醒脑子晕晕的,很认真地写了一坨shi。

代码:

#include<bits/stdc++.h>
using namespace std ;
const int maxn = 2e5 + 5 ;
int num = 0 , head[maxn] ;
int n ;
struct Edge
{
	int v , next ;
} edge[maxn << 1] ;
bool vis[maxn] ;
vector<int> b ;
set<int> s ;
void add_edge(int u , int v)
{
	edge[num].v = v ;
	edge[num].next = head[u] ;
	head[u] = num ++ ;
}
int dep[maxn] , fa[maxn][25] ;
int len , temp , d[maxn] ;
void dfs1(int f , int u , int deep)
{
   dep[u] = deep ;
   for(int i = 1 ; i <= 20 ; i ++)
   {
     int nxt = fa[u][i - 1] ;
     fa[u][i] = fa[nxt][i - 1] ;
   }
   for(int i = head[u] ; i != -1 ; i = edge[i].next)
   {
     int v = edge[i].v ;
     if(v == f)  continue ;
     fa[v][0] = u ;
     dfs1(u , v , deep + 1) ;
   }
}
int lca(int x , int y) 
{
   if(dep[x] < dep[y])  swap(x , y) ;
   for(int i = 20 ; i >= 0 ; i --)
   if(dep[fa[x][i]] >= dep[y])
   x = fa[x][i] ;
   if(x == y)  return x ;
   for(int i = 20 ; i >= 0 ; i --)
   if(fa[x][i] != fa[y][i])
   x = fa[x][i] , y = fa[y][i] ;
   return  fa[x][0] ;
}
void dfs(int f , int u)
{
	for(int i = head[u] ; i != -1 ; i = edge[i].next)
	{
		int v = edge[i].v ;
		if(v == f)  continue ;
		d[v] = d[u] + 1 ;
		if(d[v] > len)  len = d[v] , temp = v ;
		dfs(u , v) ;
	}
}
int find(int x)
{
	len = 0 ;
	temp = 0 ;
	d[x] = 0 ;
	dfs(0 , x) ;
	return temp ;
}
void dfs2(int f , int u)
{
	vis[u] = 1 ;
	for(int i = head[u] ; i != -1 ; i = edge[i].next)
	{
		int v = edge[i].v ;
		if(v == f || vis[v])  continue ;
		d[v] = d[u] + 1 ;
		if(d[v] > len)  len = d[v] , temp = v ;
		dfs(u , v) ;
	}
}
int ewai(int q , int w)
{
	for(int i = head[q] ; i != -1 ; i = edge[i].next)
	{
		int v = edge[i].v ;
		if(v != q && v != w)  return v ;
	}
}
void solve(int q , int w)
{
	int tq = q , tw = w ;
	int temp1 = q , temp2 = w ;
	int lc = lca(q , w) ;
	while(q != lc)
	{
		vis[q] = 1 , d[q] = 0 ;
		b.push_back(q) ;
		q = fa[q][0] ;
	}
	while(w != lc)
	{
		vis[w] = 1 , d[w] = 0 ;
		b.push_back(w) ;
		w = fa[w][0] ;
	}
	vis[lc] = 1 , d[lc] = 0 ;
	b.push_back(lc) ;
	len = 0 , temp = 0 ;
	for(auto u : b)  dfs2(0 , u) ;
	if(temp == 0)  temp = ewai(tq , tw) ;
	lc = lca(lc , temp) ;
	int ttemp = temp ;
	while(tq != lc)
	{
		s.insert(tq) ;
		tq = fa[tq][0] ;
	}
	while(tw != lc)
	{
		s.insert(tw) ;
		tw = fa[tw][0] ;
	}
	while(temp != lc)
	{
		s.insert(temp) ;
		temp = fa[temp][0] ;
	}
	s.insert(lc) ;
	/*int cnt = 0 ;
	for(auto x : s)
	  if(x >= 1 && x <= n)  cnt ++ ;
	printf("%d\n" , cnt - 1) ;*/
	printf("%d\n" , s.size() - 1) ;
	printf("%d %d %d\n" , temp1 , temp2 , ttemp) ;
}
int main()
{
	memset(head , -1 , sizeof(head)) ;
	scanf("%d" , &n) ;
	for(int i = 1 ; i <= n - 1 ; i ++)
	{
		int u , v ;
		scanf("%d%d" , &u , &v) ;
		add_edge(u , v) ;
		add_edge(v , u) ;
	}
	int q = find(1) ;
	int w = find(q) ;
	dfs1(0 , 1 , 1) ;
	solve(q , w) ;
	return 0 ;
}
发布了215 篇原创文章 · 获赞 12 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Irving0323/article/details/104255597
今日推荐