分析:
首先,定义点分治序为:
每次找到重心后,以重心为根,当前子树的DFS序。每一个重心的DFN序次连接,就组成了点分治序。显然,点分治序的长度是 N l o g N Nlog N NlogN级的。
现在,根据一般点分治的方式,在以X为重心时,我们要找到所有子树中的点,与X的距离。对某个点u而言,如果考虑u->x->v的一条路径,则v不能在与u相同的子树中。且这个v在点分治序上的位置是相邻的。
于是,就可以找到对任意一个点u,经过某个重心,到达另一部分的点的最长路径。
找到全局最长路径后,显然这条路径可以加入答案。现在考虑次大的路径:把最长路径拆分为两部分,其余不变。
找最大值用RMQ即可。答案可以用堆来维护,弹出M次即可。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<algorithm>
#define SF scanf
#define PF printf
#define MAXN 50010
using namespace std;
vector<int> a[MAXN],w[MAXN];
int n,m,cnt,tot;
int dist[MAXN*20];
int siz[MAXN],maxsiz[MAXN];
struct node{
int l,r,dis,ans,pos;
bool operator <(const node &a) const {
if(ans!=a.ans)
return ans<a.ans;
if(dis!=a.dis)
return dis<a.dis;
if(l!=a.l)
return l<a.l;
return r<a.r;
}
}que[MAXN*40];
priority_queue<node> q;
bool used[MAXN];
int find_g(int x,int fa,int siz1){
siz[x]=1;
maxsiz[x]=0;
int g=-1;
for(int i=0;i<int(a