bzoj 3784: 树上的路径

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

Sample Output

7
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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值