【BZOJ2051】A Problem For Fun

Description
给出一个N个结点的树,每条边有一个正整数权值,定义两个结点的距离为连接这两个结点路径上边权的和。对于每个结点i,它到其他N-1个结点都有一个距离,将这些距离从小到大排序,输出第K个距离。
Input
输入文件总共N行。第一行有两个正整数N和K。下面N-1行每行描述树的一条边(保证这些边可以构成一棵树),每行三个正整数u、v、w,表示从结点u到结点v有一条权值为w的边。输入文件保证:N <= 50000, K < N, u <= N, v <= N, w <= 10000。
Output
输出文件总共N行,每行一个正整数,第i行的数对于结点i的答案。
Sample Input
6 3
1 2 2
1 3 4
1 4 3
3 5 1
3 6 2

Sample Output
4
6
4
7
5
6

HINT

Source

其实是傻逼点分.
我人傻之前没写过点分
和Claris学了点分姿势

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define GET (ch>='0'&&ch<='9')
#define MAXN 50010
#define MAXM 1000100
using namespace std;
int n,k,Size,top,Top,rt,cnt;
int size[MAXN],f[MAXN];
int q[MAXM<<1],tail;
int rl[MAXN],rr[MAXN],el[MAXM],er[MAXM];
struct edge
{
    int to,w;
    bool vis;
    edge *next,*rev;
}e[MAXN<<1],*prev[MAXN];
struct Edge
{
    int to[2],w;
    bool vis;
    Edge *next,*rev;
}E[MAXM<<1],*Prev[MAXM];
void insert(int u,int v,int w)
{
    e[++top].to=v;e[top].next=prev[u];prev[u]=&e[top];e[top].w=w;
}
void Insert(int u,int v1,int v2,int w)
{
    E[++Top].to[0]=v1;E[Top].to[1]=v2;E[Top].w=w;E[Top].w=w;E[Top].next=Prev[u];Prev[u]=&E[Top];
}
void in(int &x)
{
    char ch=getchar();x=0;int flag=1;
    while (!GET) flag=ch=='-'?-1:flag,ch=getchar();
    while (GET) x=x*10+ch-'0',ch=getchar();x*=flag;
}
void get_G(int x,int fa)
{
    size[x]=1;f[x]=0;
    for (edge *i=prev[x];i;i=i->next)
        if (!i->vis&&i->to!=fa) get_G(i->to,x),size[x]+=size[i->to],f[x]=max(f[x],size[i->to]);
    f[x]=max(f[x],Size-size[x]);
    if (f[x]<f[rt]) rt=x;
}
void dfs(int x,int fa,int dis)
{
    q[++tail]=dis;
    for (edge *i=prev[x];i;i=i->next)
        if (!i->vis&&i->to!=fa) dfs(i->to,x,i->w+dis);
}
void dfs2(int x,int fa,int dis)
{
    Insert(x,rt,cnt,dis);q[++tail]=dis;
    for (edge *i=prev[x];i;i=i->next)
        if (!i->vis&&i->to!=fa) dfs2(i->to,x,i->w+dis);
}
void solve(int x)
{
    rl[x]=++tail;q[tail]=0;
    for (edge *i=prev[x];i;i=i->next)
        if (!i->vis)    dfs(i->to,x,i->w);
    rr[x]=tail;sort(q+rl[x],q+rr[x]+1);
    for (edge *i=prev[x];i;i=i->next)
        if (!i->vis)    el[++cnt]=tail+1,dfs2(i->to,x,i->w),er[cnt]=tail,sort(q+el[cnt],q+er[cnt]+1);
    for (edge *i=prev[x];i;i=i->next)
        if (!i->vis)    i->rev->vis=1,f[0]=Size=size[i->to],rt=0,get_G(i->to,rt),solve(rt);
}
int Query(int L,int R,int val)
{
    int l=L,r=R,mid;R=l-1;
    while (l<=r)
    {
        mid=l+r>>1;
        if (q[mid]<=val)    l=mid+1,R=mid;
        else    r=mid-1;
    }
    return R-L+1;
}
int check(int x,int val)
{
    int ret=Query(rl[x],rr[x],val)-1;
    for (Edge *i=Prev[x];i;i=i->next)
        ret+=Query(rl[i->to[0]],rr[i->to[0]],val-i->w)-Query(el[i->to[1]],er[i->to[1]],val-i->w);
    return ret;
}
int query(int x)
{
    int l=1,r=10000*(n-1),mid;
    while (l<r)
    {
        mid=l+r>>1;
        if (check(x,mid)<k) l=mid+1;
        else    r=mid;
    }
    return l;
}
int main()
{
    in(n);in(k);
    for (int i=1;i<n;i++)
    {
        int u,v,w;in(u);in(v);in(w);
        insert(u,v,w);insert(v,u,w);
        e[top].rev=&e[top-1];e[top-1].rev=&e[top];
    }
    Size=f[0]=n;
    get_G(1,0);solve(rt);
    for (int i=1;i<=n;i++)  printf("%d\n",query(i));
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值