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 )
做法同NOI2010超级钢琴。很神奇的做法
我们做树分治的时候维护单条链的长度和可以和哪些链连接起来([L,R]区间)
然后用堆维护五元组(s,l,r,d,x)表示(当前段,可以到达的区间的左端点,可以到达的区间右端点,最大值的位置,最大值的ans)
然后最大值用线段树或者ST表维护下都可以
推荐ST表虽然我写的是线段树
#include<queue>
#include<vector>
#include<cstdio>
#include<algorithm>
using namespace std;
struct line
{
int s,t;
int x;
int next;
}a[100001];
int head[50001];
int edge;
inline void add(int s,int t,int x)
{
a[edge].next=head[s];
head[s]=edge;
a[edge].s=s;
a[edge].t=t;
a[edge].x=x;
}
struct tree
{
int l,r;
int loc;
int m;
}tr[4000001];
int s[500001];
inline void up(int p)
{
if(tr[p*2].m>tr[p*2+1].m)
{
tr[p].m=tr[p*2].m;
tr[p].loc=tr[p*2].loc;
}
else
{
tr[p].m=tr[p*2+1].m;
tr[p].loc=tr[p*2+1].loc;
}
}
inline void build(int p,int l,int r)
{
tr[p].l=l;
tr[p].r=r;
if(l!=r)
{
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
up(p);
}
else
{
tr[p].m=s[l];
tr[p].loc=l;
}
}
tree nw;
inline tree ask(int p,int l,int r)
{
if(l<=tr[p].l&&tr[p].r<=r)
return tr[p];
else
{
int mid=(tr[p].l+tr[p].r)/2;
tree ans1=nw,ans2=nw,as=nw;
bool flag1=false,flag2=false;
if(l<=mid)
{
flag1=true;
ans1=ask(p*2,l,r);
}
if(r>mid)
{
flag2=true;
ans2=ask(p*2+1,l,r);
}
if(flag1)
{
if(flag2)
{
if(ans1.m>ans2.m)
{
as.m=ans1.m;
as.loc=ans1.loc;
}
else
{
as.m=ans2.m;
as.loc=ans2.loc;
}
}
else
as=ans1;
}
else
as=ans2;
return as;
}
}
int son[50001],mson[50001];
bool v[50001];
int mini,minx;
int dis[50001];
int fa[50001];
inline void getroot(int d,int s)
{
son[d]=0;
mson[d]=0;
int i;
for(i=head[d];i!=0;i=a[i].next)
{
int t=a[i].t;
if(!v[t]&&t!=fa[d])
{
fa[t]=d;
getroot(t,s);
son[d]+=son[t]+1;
mson[d]=max(mson[d],son[t]+1);
}
}
int temp=max(mson[d],s-mson[d]-1);
if(mson[d]<minx)
{
minx=temp;
mini=d;
}
}
int p;
inline void dfs(int d)
{
int i;
for(i=head[d];i!=0;i=a[i].next)
{
int t=a[i].t;
if(!v[t]&&t!=fa[d])
{
fa[t]=d;
dis[t]=dis[d]+a[i].x;
p++;
s[p]=dis[t];
dfs(t);
}
}
}
struct gets
{
int l,r;
}px[1000001];
inline void solve(int d)
{
v[d]=true;
int i,j;
int pp=p;
for(i=head[d];i!=0;i=a[i].next)
{
int t=a[i].t;
if(!v[t])
{
dis[t]=a[i].x;
int p1=p;
p++;
s[p]=dis[t];
fa[t]=0;
dfs(t);
for(j=p1+1;j<=p;j++)
{
px[j].l=pp+1;
px[j].r=p1;
}
}
}
for(i=head[d];i!=0;i=a[i].next)
{
int t=a[i].t;
if(!v[t])
{
minx=2100000000;
mini=0;
fa[t]=0;
getroot(t,son[d]);
solve(mini);
}
}
}
struct findx
{
int s;
int d;
int l,r;
long long x;
bool operator <(findx y) const
{
return x<y.x;
}
};
priority_queue <findx> Q;
int main()
{
// freopen("path.in","r",stdin);
// freopen("path.out","w",stdout);
int n,m;
scanf("%d%d",&n,&m);
int i,ss,tt,x;
for(i=1;i<=n-1;i++)
{
scanf("%d%d%d",&ss,&tt,&x);
edge++;
add(ss,tt,x);
edge++;
add(tt,ss,x);
}
minx=2100000000;
mini=0;
getroot(1,n);
solve(mini);
build(1,1,p);
for(i=1;i<=p;i++)
{
int ss=px[i].l,tt=px[i].r;
if(ss>tt)
continue;
tree x=ask(1,ss,tt);
findx t;
t.s=i;
t.d=x.loc;
t.l=ss;
t.r=tt;
t.x=x.m+s[t.s];
Q.push(t);
}
for(i=1;i<=p;i++)
{
findx t;
t.s=i;
t.d=i;
t.l=i;
t.r=i;
t.x=s[i];
Q.push(t);
}
while(m>0)
{
m--;
findx t=Q.top();
printf("%d\n",t.x);
Q.pop();
tree x;
findx t1,t2;
if(t.d-1>=t.l)
{
x=ask(1,t.l,t.d-1);
t1.s=t.s;
t1.d=x.loc;
t1.l=t.l;
t1.r=t.d-1;
t1.x=x.m+s[t.s];
Q.push(t1);
}
if(t.d+1<=t.r)
{
x=ask(1,t.d+1,t.r);
t2.s=t.s;
t2.d=x.loc;
t2.l=t.d+1;
t2.r=t.r;
t2.x=x.m+s[t.s];
Q.push(t2);
}
}
return 0;
}