【BZOJ4317】Atm的树

Description

Atm有一段时间在虐qtree的题目,于是,他满脑子都是tree,tree,tree……
于是,一天晚上他梦到自己被关在了一个有根树中,每条路径都有边权,一个神秘的声音告诉他,每个点到其他的点有一个距离(什么是距离不用说吧),他需要对于每个点回答:从这个点出发的第k小距离是多少;
如果atm不能回答出来,那么明天4019的闹钟将不会响,4019全寝可能就迟到了,所以atm希望你帮帮他。
Input

第一行,两个正整数n,k,表示树的点数,询问的是第几小距离;
第二~n行,每行三个正整数x,y,w,表示x和y之间有一条边,x为父亲,边权为w;
Output

n行, 每行一个数,第i行输出从i开始第k小距离
Sample Input

5 2

1 5 2

1 2 4

2 3 6

2 4 5

Sample Output

4

5

10

9

6
HINT

100% n<=15000, 边权在1~10之间,为了方便,保证1为根;

Source

同BZOJ2051

发着烧我好痛苦T_T
文化课会让发烧更加严重所以来写点代码转移注意力以不那么难受

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define GET (ch>='0'&&ch<='9')
#define MAXN 15010
#define MAXM 500010
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[MAXN],er[MAXN];
void in(int &x)
{
    char ch=getchar();x=0;
    while (!GET)    ch=getchar();
    while (GET) x=x*10+ch-'0',ch=getchar();
}
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].w=w;e[top].next=prev[u];prev[u]=&e[top];
}
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].next=Prev[u];Prev[u]=&E[Top];
}
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,dis+i->w);
}
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,dis+i->w);
}
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=(l+r)>>1;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=10*(n-1),mid=(l+r)>>1;
    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);int u,v,w;
    for (int i=1;i<n;i++)
    {
        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));
}

你可能感兴趣的:(点分治树)