题意
内存限制:256 MiB
时间限制:1000 ms
给定一棵 N N N 个结点的树,结点用正整数 1 … N 1…N 1…N 编号,每条边有一个正整数权值。用 d ( a , b ) d(a,b) d(a,b) 表示从结点 a a a 到结点 b b b 路径上经过边的权值和,其中要求 a < b a<b a<b 。将这 N × ( N − 1 ) 2 \frac{N \times (N-1)}{2} 2N×(N−1) 个距离值从大到小排序,输出前 M M M 个距离值。
N ≤ 50000 N \leq 50000 N≤50000 , M ≤ m i n ( N × ( N − 1 ) 2 , 300000 ) M \leq min(\frac{N \times (N-1)}{2},300000) M≤min(2N×(N−1),300000)
题解
考虑点分,建立出点分序,表示的时点分时经过的点,空间为 O ( n log n ) O(n \log n) O(nlogn) ,每个点 x x x 对应三元组 l , r , v {l,r,v} l,r,v 表示 x x x 点到重心的距离为 v v v ,且可以取 [ l , r ] [l,r] [l,r] 中的点组合形成一条链
然后对于每个点找到其最长链并且加入堆中,形成四元组 l , r , m a x l , r , x {l,r,max_{l,r},x} l,r,maxl,r,x ,然后取出堆中的元素,并且找到 m a x l , r max_{l,r} maxl,r 所在的位置 p p p ,并且将 l , p − 1 , m a x l , p − 1 , x {l,p-1,max_{l,p-1},x} l,p−1,maxl,p−1,x 和 p + 1 , r , m a x p + 1 , r , x {p+1,r,max_{p+1,r},x} p+1,r,maxp+1,r,x 加入堆中,循环 m m m 次即可
寻找最大值可用 s t st st 表实现
#include <bits/stdc++.h>
#define I inline
using namespace std;
const int N=5e4+5;bool vis[N];
int n,m,sz[N],son[N],rt,o,hd[N],V[N*2];
int W[N*2],nx[N*2],t,f[N*16][21],L,R,Lg[N*16];
struct O{int l,r,v;}p[N*16];
struct Q{
int l,r,x,y;
I friend bool operator < (Q A,Q B){
return p[A.x].v+p[A.y].v<p[B.x].v+p[B.y].v;
}
};
priority_queue<Q>q;
I void add(int u,int v,int w){
nx[++t]=hd[u];V[hd[u]=t]=v;W[t]=w;
}
#define v V[i]
I void getrt(int x,int fa){
sz[x]=1;son[x]=0;
for (int i=hd[x];i;i=nx[i])
if (v!=fa && !vis[v])
getrt(v,x),sz[x]+=sz[v],
son[x]=max(son[x],sz[v]);
son[x]=max(o-sz[x],son[x]);
if (son[x]<son[rt]) rt=x;
}
I void dfs(int x,int fa,int w){
p[++t]=(O){L,R,w};f[t][0]=t;
for (int i=hd[x];i;i=nx[i])
if (v!=fa && !vis[v])
dfs(v,x,w+W[i]);
}
I void work(int x){
L=R=++t;f[t][0]=t;
p[t]=(O){t,t,0};vis[x]=1;
for (int i=hd[x];i;i=nx[i])
if (!vis[v]) dfs(v,x,W[i]),R=t;
for (int i=hd[x];i;i=nx[i])
if (!vis[v])
rt=0,o=sz[v],getrt(v,x),work(rt);
}
#undef v
I int ax(int x,int y){
return p[x].v>p[y].v?x:y;
}
I int query(int l,int r){
int i=Lg[r-l+1];
return ax(f[l][i],f[r-(1<<i)+1][i]);
}
I void push(int l,int r,int x){
q.push((Q){l,r,x,query(l,r)});
}
int main(){
son[0]=1e9;
scanf("%d%d",&n,&m);
for (int x,y,z,i=1;i<n;i++)
scanf("%d%d%d",&x,&y,&z),
add(x,y,z),add(y,x,z);
t=0;o=n;getrt(1,0);work(rt);
for (int i=2;i<=t;i++) Lg[i]=Lg[i>>1]+1;
for (int i=t;i;i--)
for (int j=1;i+(1<<j)<=t+1;j++)
f[i][j]=ax(f[i][j-1],f[i+(1<<(j-1))][j-1]);
for (int i=1;i<=t;i++) push(p[i].l,p[i].r,i);
while(m--){
Q k=q.top();q.pop();
printf("%d\n",p[k.x].v+p[k.y].v);
if (k.y>k.l) push(k.l,k.y-1,k.x);
if (k.y<k.r) push(k.y+1,k.r,k.x);
}
return 0;
}