题意
内存限制:256 MiB
时间限制:1000 ms
给定一棵 NNN 个结点的树,结点用正整数 1…N1…N1…N 编号,每条边有一个正整数权值。用 d(a,b)d(a,b)d(a,b) 表示从结点 aaa 到结点 bbb 路径上经过边的权值和,其中要求 a<ba<ba<b 。将这 N×(N−1)2\frac{N \times (N-1)}{2}2N×(N−1) 个距离值从大到小排序,输出前 MMM 个距离值。
N≤50000N \leq 50000N≤50000 , M≤min(N×(N−1)2,300000)M \leq min(\frac{N \times (N-1)}{2},300000)M≤min(2N×(N−1),300000)
题解
考虑点分,建立出点分序,表示的时点分时经过的点,空间为 O(nlogn)O(n \log n)O(nlogn) ,每个点 xxx 对应三元组 l,r,v{l,r,v}l,r,v 表示 xxx 点到重心的距离为 vvv ,且可以取 [l,r][l,r][l,r] 中的点组合形成一条链
然后对于每个点找到其最长链并且加入堆中,形成四元组 l,r,maxl,r,x{l,r,max_{l,r},x}l,r,maxl,r,x ,然后取出堆中的元素,并且找到 maxl,rmax_{l,r}maxl,r 所在的位置 ppp ,并且将 l,p−1,maxl,p−1,x{l,p-1,max_{l,p-1},x}l,p−1,maxl,p−1,x 和 p+1,r,maxp+1,r,x{p+1,r,max_{p+1,r},x}p+1,r,maxp+1,r,x 加入堆中,循环 mmm 次即可
寻找最大值可用 ststst 表实现
#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;
}