Description
给定一个N个结点的树,结点用正整数1..N编号。每条边有一个正整数权值。用d(a,b)表示从结点a到结点b路边上经过边的权值。其中要求a<b.将这n*(n-1)/2个距离从大到小排序,输出前M个距离值。
Input
第一行两个正整数N,M
下面N-1行,每行三个正整数a,b,c(a,b<=N,C<=10000)。表示结点a到结点b有一条权值为c的边。
Output
共M行,如题所述.
Sample Input
5 10
1 2 1
1 3 2
2 4 3
2 5 4
1 2 1
1 3 2
2 4 3
2 5 4
Sample Output
7
7
6
5
4
4
3
3
2
1
7
6
5
4
4
3
3
2
1
HINT
N<=50000,M<=Min(300000,n*(n-1) /2 )
题解:
其实就是超级钢琴那个题扩展到树上.
点分治过程中把访问到的点记下来可以得到一个点分治序列并记录他们的dis值.
这个序列中的每个点x都可以求出一个[l,r],表示点x可以与序列中[l,r]的点形成链.
对于每个点都可以维护一个4元组{l,r,h,mx}
分别表示这个点在点分治序列中的编号是h,可以与序列中[l,r]的点形成链,[l,r]中dis的最大值在mx位置.
这样这个点所形成链的最大值就是xu[h]+xu[mx],xu表示点分治序列并且存的是dis值.
用一个堆来维护这些4元组.
取出一个四元组{l,r,h,mx}之后将这个4元组裂解成{l,mx-1.h,max(l,mx-1)},{mx+1,r,h,max(mx+1,r)}再加入堆.
询问区间最值可以用st表实现.
取M次堆顶即可.
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#include<cmath>
#define N 50010
#define M 300010
int h[N],n,m,root,size[N],sum,vis[N],cnt,next[N<<1],point[N],dis[N],x,y,v;
int l,r,xu[N*20],id,f[20][N*20];
struct edge{int st,en,v;}e[N<<1];
struct interval{int l,r;}p[N*20];
struct use{int l,r,h,mq;};
using namespace std;
priority_queue<use>q;
bool operator<(use a,use b){
return xu[a.h]+xu[a.mq]<xu[b.h]+xu[b.mq];
}
int read(){
int x(0);char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
void add(int x,int y,int v){
next[++cnt]=point[x];point[x]=cnt;
e[cnt].st=x;e[cnt].en=y;e[cnt].v=v;
}
void getroot(int x,int fa){
size[x]=1;h[x]=0;
for (int i=point[x];i;i=next[i])
if (e[i].en!=fa&&!vis[e[i].en]){
getroot(e[i].en,x);
size[x]+=size[e[i].en];
h[x]=max(h[x],size[e[i].en]);
}
h[x]=max(h[x],sum-size[x]);
if (h[x]<h[root]) root=x;
}
void getroute(int x,int fa){
xu[++id]=dis[x];p[id]={l,r};
for(int i=point[x];i;i=next[i])
if (e[i].en!=fa&&(!vis[e[i].en])){
dis[e[i].en]=dis[x]+e[i].v;
getroute(e[i].en,x);
}
}
void solve(int x){
vis[x]=1;
xu[++id]=0;p[id]={0,0};l=r=id;
for (int i=point[x];i;i=next[i])
if (!vis[e[i].en]){
dis[e[i].en]=e[i].v;
getroute(e[i].en,x);
r=id;
}
for (int i=point[x];i;i=next[i])
if (!vis[e[i].en]){
root=0;
sum=size[e[i].en];
//cout<<e[i].en<<' '<<sum<<endl;
getroot(e[i].en,0);
//cout<<root<<endl;while (1);
solve(root);
}
}
int query(int l,int r){
int t;
t=(int)(log(r-l+1.0)/log(2.0));
if (xu[f[t][l]]>xu[f[t][r-(1<<t)+1]])
return f[t][l];
else return f[t][r-(1<<t)+1];
}
void pre(){
for (int i=1;i<=id;i++) f[0][i]=i;
for (int i=1;i<=19;i++)
for (int j=1;j<=id;j++)
if (j+(1<<i)-1<=id){
if (xu[f[i-1][j]]>xu[f[i-1][j+(1<<i>>1)]])
f[i][j]=f[i-1][j];
else f[i][j]=f[i-1][j+(1<<i>>1)];
}
else break;
for (int i=1;i<=id;i++)
if (p[i].l!=0)
q.push(use{p[i].l,p[i].r,i,query(p[i].l,p[i].r)});
}
void getans(){
for (int i=1;i<=m;i++){
use t=q.top();q.pop();
printf("%d\n",xu[t.mq]+xu[t.h]);
if (t.l<=t.mq-1) q.push(use{t.l,t.mq-1,t.h,query(t.l,t.mq-1)});
if (t.mq+1<=t.r) q.push(use{t.mq+1,t.r,t.h,query(t.mq+1,t.r)});
}
}
int main(){
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
n=read();m=read();
for (int i=1;i<n;i++){
x=read();y=read();v=read();
add(x,y,v);add(y,x,v);
}
sum=n;h[root]=n;
getroot(1,0);
//for (int i=1;i<=n;i++) cout<<h[i]<<endl;
solve(root);
pre();
getans();
}