bzoj4738: 汽水

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;
}
原文地址:https://www.cnblogs.com/ccz181078/p/6768797.html