UOJ # 276. [2016] Tsinghua training soda

TMD actually wrote a blog is not enough sober, then write another went to sleep

First, a look at the subject will find it possible to put a fraction of planning , which we now want to minimize \ (| \ frac {\ sum_ {i = 1} ^ {len} w_i} {len} -k | \)

Consider binary answer \ (X \) , removed the way the absolute value, i.e. \ (- X \ Le \ FRAC {\ sum_. 1 = {I}} ^ {len len W_i} {} -k \ Le X \) , found In fact, as long as conditions are satisfied:

\[\sum_{i=1}^{len} w_i-k+x \ge 0\]

\ [\ Sum_ {i = 1} ^ {} len w_i-kx \ le 0 \]

So \ (k \) do not control directly lose to consider is to find a path to meet the above two conditions

Then considering that this is the tree problem, we consider the point of divide and conquer , if you look into the first condition is very simple, as long as the center of the partition to the right side of all the points and get out and find two (or one) is greater than the length \ (0 \) is to

Then there is how to do the second requirement is not difficult to find because only take two chains, so we can meet under a situation to minimize the value of the second, and after this you can sort two points sweep resolved

Take note of both chains in the same situation in the sub-tree to sentence a bit, the overall complexity of the \ (O (n \ log ^ 2 n) \)

#include<cstdio>
#include<iostream>
#include<algorithm>
#define int long long
#define RI register int
#define CI const int&
using namespace std;
typedef long double DB;
const int N=100005,INF=1e18;
const DB EPS=1e-3;
struct edge
{
    int to,nxt; DB v1,v2;
}e[N<<1]; int n,head[N],cnt,k,x,y,z;
inline void addedge(CI x,CI y,CI z)
{
    e[++cnt]=(edge){y,head[x],(DB)z-k,(DB)z-k}; head[x]=cnt;
    e[++cnt]=(edge){x,head[y],(DB)z-k,(DB)z-k}; head[y]=cnt;
}
class Point_Division_Solver
{
    private:
        struct data
        {
            int id; DB d1,d2;
            friend inline bool operator < (const data& A,const data& B)
            {
                return A.d1<B.d1;
            }
        }d[N]; int size[N],mx[N],ots,tot,rt; bool vis[N];
        #define to e[i].to
        inline void getrt(CI now,CI fa=0)
        {
            size[now]=1; mx[now]=0; for (RI i=head[now];i;i=e[i].nxt) if (to!=fa&&!vis[to])
            getrt(to,now),size[now]+=size[to],mx[now]=max(mx[now],size[to]);
            if ((mx[now]=max(mx[now],ots-size[now]))<mx[rt]) rt=now;
        }
        inline void travel(CI now,CI fr,CI fa,const DB& dis1,const DB& dis2)
        {
            d[++tot]=(data){fr,dis1,dis2}; for (RI i=head[now];i;i=e[i].nxt)
            if (to!=fa&&!vis[to]) travel(to,fr,now,dis1+e[i].v1,dis2+e[i].v2);
        }
        inline void insert(int& mi,int& smi,CI p)
        {
            if (d[p].d2<d[mi].d2) { if (d[p].id!=d[mi].id) smi=mi; mi=p; }
            else if (d[p].d2<d[smi].d2&&d[p].id!=d[mi].id) smi=p;
        }
        inline bool judge(CI rt)
        {
            RI i,pos,mi,smi; for (d[tot=1]=(data){rt,0,0},i=head[rt];i;i=e[i].nxt)
            if (!vis[to]) travel(to,to,rt,e[i].v1,e[i].v2); 
            sort(d+1,d+tot+1); d[0].d2=INF; for (i=pos=1;d[i].d1<0;++i,++pos);
            for (mi=smi=0;i<=tot;++i)
            {
                while (pos>1&&d[pos-1].d1+d[i].d1>=0) insert(mi,smi,--pos);
                if (d[mi].id!=d[i].id&&d[mi].d2+d[i].d2<=0) return 1;
                if (d[mi].id==d[i].id&&d[smi].d2+d[i].d2<=0) return 1;
                insert(mi,smi,i);
            }
            return 0;
        }
        inline bool solve(CI now)
        {
            vis[now]=1; if (judge(now)) return 1;
            for (RI i=head[now];i;i=e[i].nxt) if (!vis[to])
            {
                mx[rt=0]=INF; ots=size[to]; getrt(to);
                if (solve(rt)) return 1;
            }
            return 0;
        }
        #undef to
    public:
        inline bool check(const DB& x)
        {
            //printf("%lld : ",(int)x); 
            RI i; for (i=1;i<=n;++i) vis[i]=0;
            for (i=1;i<=cnt;++i) e[i].v1+=x,e[i].v2-=x;
            mx[rt=0]=INF; ots=n; getrt(1); bool flag=solve(rt);
            for (i=1;i<=cnt;++i) e[i].v1-=x,e[i].v2+=x; return flag;
        }
}PD;
signed main()
{
    //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    RI i; for (scanf("%lld%lld",&n,&k),i=1;i<n;++i)
    scanf("%lld%lld%lld",&x,&y,&z),addedge(x,y,z);
    DB l=0,r=1e13,mid; while (r-l>EPS)
    if (PD.check(mid=(l+r)/2.0)) r=mid; else l=mid;
    return printf("%lld",(int)(r)),0;
}

Guess you like

Origin www.cnblogs.com/cjjsb/p/11616519.html