时间限制: 1 Sec 内存限制: 256 MB
题目描述
给定一棵N个结点的树,结点用正整数1..N编号,每条边有一个正整数权值。用d(a,b)表示从结点a到结点b路径上经过边的权值和,其中要求a
类似于noi2009超级钢琴的做法,先用点分治找出每个点能和它联通的点的区间,然后把这些东西扔到一个堆里,用主席树维护区间第K大即可。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<algorithm>
#define N 50010
#define inf 1050000000
using namespace std;
int n,m,cnt,size[N],w[N],fa[N],dis[N],s[N*17],c[N*17];
int k,la[N],ff[N*2],q[N],flag[N],st,maxn,tot;
struct node{int a,b,c;}map[N*2];
struct wbs{
int l,r,pos,num1,num2;
bool operator<(const wbs &cyc)
const{return num1+num2<cyc.num1+cyc.num2;}
};
struct point{int lc,rc,size;}t[N*270];
priority_queue<wbs>h;
void add(int a,int b,int c)
{
map[++k]=(node){a,b,c};ff[k]=la[a];la[a]=k;
map[++k]=(node){b,a,c};ff[k]=la[b];la[b]=k;
}
int find(int S)
{
int l=1,r=2,num=inf,res;q[1]=S;flag[S]=1;fa[S]=0;
while(l<r)
{
int x=q[l];l++;size[x]=1;w[x]=0;
for(int a=la[x];a;a=ff[a])
if(!flag[map[a].b])
q[r]=map[a].b,flag[q[r]]=1,fa[q[r]]=x,r++;
}
if(r==2)return -1;
for(int i=r-1;i;i--)
{
int x=q[i];flag[x]=0;
if(fa[x])size[fa[x]]+=size[x],w[fa[x]]=max(w[fa[x]],size[x]);
if(max(w[x],r-size[x]-1)<num)num=max(w[x],r-size[x]-1),res=x;
}
return res;
}
void work(int S,int top,int num)
{
int l=1,r=2,end=cnt,tmp=0;
q[1]=S;dis[S]=num;flag[S]=1;
while(l<r)
{
int x=q[l];l++;s[++cnt]=dis[x];tmp=max(tmp,dis[x]);
for(int a=la[x];a;a=ff[a])
if(!flag[map[a].b])
q[r]=map[a].b,flag[q[r]]=1,dis[q[r]]=dis[x]+map[a].c,r++;
}
for(int i=r-1;i;i--)
{
int x=q[i];flag[x]=0;
h.push((wbs){st,end,end-st+1,dis[x],maxn});
}
maxn=max(maxn,tmp);
}
void solve(int x)
{
int rt=find(x);
if(rt==-1)return;
flag[rt]=1;st=++cnt;maxn=0;s[cnt]=0;
for(int a=la[rt];a;a=ff[a])
if(!flag[map[a].b])work(map[a].b,rt,map[a].c);
for(int a=la[rt];a;a=ff[a])
if(!flag[map[a].b])solve(map[a].b);
}
class seg_tree
{
public:
void modify(int x,int pre,int l,int r,int des)
{
t[x]=t[pre];t[x].size++;
if(l==r)return;
int mid=l+r>>1;
if(des<=mid)modify(t[x].lc=++tot,t[pre].lc,l,mid,des);
else modify(t[x].rc=++tot,t[pre].rc,mid+1,r,des);
}
int qry(int x,int pre,int l,int r,int des)
{
if(l==r)return c[l];
int mid=l+r>>1,num=t[t[x].lc].size-t[t[pre].lc].size;
if(des<=num)qry(t[x].lc,t[pre].lc,l,mid,des);
else qry(t[x].rc,t[pre].rc,mid+1,r,des-num);
}
}T;
int main()
{
int a,b,v;
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++)
scanf("%d%d%d",&a,&b,&v),add(a,b,v);
solve(1);
for(int i=1;i<=cnt;i++)c[i]=s[i];
sort(c+1,c+cnt+1);tot=cnt;
int Tnum=unique(c+1,c+cnt+1)-c-1;
for(int i=1;i<=cnt;i++)
T.modify(i,i-1,1,Tnum,lower_bound(c+1,c+Tnum+1,s[i])-c);
while(m--&&h.size())
{
wbs x=h.top();h.pop();
printf("%d\n",x.num1+x.num2);
if(x.pos==1)continue;
x.num2=T.qry(x.r,x.l-1,1,Tnum,--x.pos);
h.push(x);
}
return 0;
}