Description
牛牛来到了一个盛产汽水的国度旅行。这个国度的地图上有n个城市,这些城市之间用n?1条道路连接,任意两个城
市之间,都存在一条路径连接。这些城市生产的汽水有许多不同的风味,在经过道路 i 时,牛牛会喝掉wi的汽水
。牛牛非常喜欢喝汽水,但过量地饮用汽水是有害健康的,因此,他希望在他旅行的这段时间内,平均每天喝到的
汽水的量尽可能地接近给定的一个正整数k。同时,牛牛希望他的旅行计划尽可能地有趣,牛牛会先选择一个城市
作为起点,然后每天通过一条道路,前往一个没有去过的城市,最终选择在某一个城市结束旅行。牛牛还要忙着去
喝可乐,他希望你帮他设计出一个旅行计划,满足每天 |平均每天喝到的汽水-k| 的值尽量小(其中天数至少为1
),请你告诉他这个最小值。
Input
第一行两个正整数n,k。
接下来n-1行,每行三个正整数ui,vi,wi,表示城市ui和城市vi之间有一条长度为wi的道路连接。
n≤5×10^4,0≤wi≤10^13,0≤k≤10^13。
同一行相邻的两个整数均用一个空格隔开。
Output
一行一个整数,表示 |平均每天喝到的汽水-k|的最小值的整数部分
即你只要将这个最小值向下取整然后输出即可。
类似一般的分数规划,二分答案,转化为是否存在一条路径,两个权值均为正数
点分治并用平衡树维护一下已处理路径的答案
时间复杂度$O(nlog^2(n)log(max(a_i)))$
#include<cstdio> #include<algorithm> #include<cstdlib> typedef long long i64; template<class T> void _(T&x){ x=0; int c=getchar(),f=1; while(c<48)c=='-'&&(f=-1),c=getchar(); while(c>47)x=x*10+c-48,c=getchar(); x*=f; } const int N=50007; int n;i64 k; int es[N*2],enx[N*2],e0[N],ep=2; i64 ev[N*2]; i64 _0=0,_1=0,maxv=1ll<<61,now; int _2=0; i64 abs(i64 x){return x>0?x:-x;} void mins(i64&a,i64 b){if(a>b)a=b;} void f0(int w,int pa){ if(_2)mins(maxv,abs(_1-k*_2)/_2); for(int i=e0[w];i;i=enx[i]){ int u=es[i]; if(u==pa)continue; _1+=ev[i],++_2; f0(u,w); _1-=ev[i],--_2; } } bool ed[N],flag; int sz[N],SZ,CG; void f2(int w,int pa){ sz[w]=1; for(int i=e0[w];i;i=enx[i]){ int u=es[i]; if(u==pa||ed[u])continue; f2(u,w); sz[w]+=sz[u]; } } void f3(int w,int pa){ bool is=sz[w]*2>=SZ; for(int i=e0[w];i;i=enx[i]){ int u=es[i]; if(u==pa||ed[u])continue; f3(u,w); if(sz[u]*2>SZ)is=0; } if(is)CG=w; } struct pos{ i64 x,y; }vs[N]; struct node{ pos w; node*lc,*rc; int rnd; void init(pos _w){ w=_w; rnd=rand()|1; lc=rc=0; } }mem[N],*ms[N],*rt; int mp=0; node*merge(node*a,node*b){ if(!a)return b; if(!b)return a; if(a->rnd>b->rnd){ a->rc=merge(a->rc,b); return a; }{ b->lc=merge(a,b->lc); return b; } } void splitx(node*w,node*&l,node*&r,i64 x){ if(!w){ l=r=0; return; } if(x<w->w.x){ splitx(w->lc,l,w->lc,x); r=w; }else{ l=w; splitx(w->rc,w->rc,r,x); } } void splity(node*w,node*&l,node*&r,i64 x){ if(!w){ l=r=0; return; } if(x<w->w.y){ splity(w->lc,l,w->lc,x); r=w; }else{ l=w; splity(w->rc,w->rc,r,x); } } void rec(node*&w){ if(!w)return; rec(w->lc); rec(w->rc); ms[mp++]=w; w=0; } bool chk(node*w,i64 x,i64 y){ while(w){ if(w->w.x<=x)w=w->rc; else{ if(w->w.y<y)return 1; w=w->lc; } } return 0; } int vp=0; void f4(int w,int pa,i64 v1,i64 v2,int dep){ if(v1>0&&v2<0)flag=1; else{ if(chk(rt,-v1,-v2))flag=1; vs[vp++]=(pos){v1,v2}; } if(!flag) for(int i=e0[w];i;i=enx[i]){ int u=es[i]; if(u==pa||ed[u])continue; f4(u,w,v1+ev[i]-k+now,v2+ev[i]-k-now,dep+1); } } int cs[N],cp,ee[N]; bool cmp(int a,int b){ return sz[a]<sz[b]; } bool chk(i64 M){ flag=0; now=M+1; rec(rt); for(int i=1;i<=cp;++i){ int w=cs[i]; vp=0; f4(w,0,ev[ee[w]]-k+now,ev[ee[w]]-k-now,1); if(flag){ maxv=M; return 1; } if(i==cp)break; while(vp){ pos w=vs[--vp]; if(chk(rt,w.x,w.y+1))continue; node*p1,*p2,*p3; splitx(rt,p1,p2,w.x); splity(p1,p1,p3,w.y); rec(p3); node*a=ms[--mp]; a->init(w); rt=merge(p1,merge(a,p2)); } } return 0; } void f1(int w){ f2(w,0);SZ=sz[w]; f3(w,0);w=CG; f2(w,0); ed[w]=1; cp=0; for(int i=e0[w];i;i=enx[i]){ int u=es[i]; if(!ed[u])cs[++cp]=u,ee[u]=i; } if(maxv>0&&chk(maxv-1)){ i64 L=0,R=maxv-1,M; while(L<=R){ M=L+R>>1; if(chk(M))R=M-1; else L=M+1; } } for(int i=e0[w];i;i=enx[i]){ int u=es[i]; if(!ed[u])f1(u); } } int main(){ _(n);_(k); for(int i=0;i<n;++i)ms[mp++]=mem+i; for(int i=1;i<n;++i){ int a,b;i64 c; _(a);_(b);_(c); es[ep]=b;enx[ep]=e0[a];ev[ep]=c;e0[a]=ep++; es[ep]=a;enx[ep]=e0[b];ev[ep]=c;e0[b]=ep++; } for(int i=1;i<=n;++i)if(rand()%10000==1||i==1)f0(i,0); f1(1); printf("%lld",maxv); return 0; }