1. 程式人生 > >【BZOJ2051】A Problem For Fun

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