想要很对劲的讲解,请点击这里

题目大意

有一棵\(n\)(\(n\leq 50000\))个节点的树,有边权

求一条路径使该路径的边权平均值最接近给出的一个数\(k\)

输出边权平均值下取整的整数部分

题解

有关路径的边权平均值可以二分来做

假设已二分出边权平均值与\(k\)的差不超过\(m\),则应存在一条简单路径,路径上的\(p\)条边满足:

\[-m\leq\frac{\sum_{i=1}^{p}{w_i}}{p}-k\leq m
\]

两边同乘\(p\),得:

\[-m*p\leq\sum_{i=1}^{p}{w_i-k}\leq m*p
\]

也就是$$\begin{cases}{\sum_{i=1}^{p}{(w_i-k+m)}}\geq 0\\sum_{i=1}^{p}{(w_i-k-m)}\leq 0\end{cases}$$

那么设\(a_i=w_i-k+m,b_i=w_i-k-m\),问题就变成了判断图中是否存在一条简单路径,满足\(\Sigma a_i\geq 0\)且\(\Sigma b_i\leq 0\)

这种在树上找满足某个条件的链的问题可以用点分治解决

设某点\(i\)到当前区域的重心的简单路径上,\(a_k\)之和为\(A_i\),\(b_k\)之和为\(B_i\)

则问题转化为找两点\(i\),\(j\)不属于当前区域的重心的同一子树,且\(A_i+A_j\geq0\),\(B_i+B_j\leq0\)

也可以看成是对于点\(i\),所有\(A_j\geq-A_i\)的点\(j\)中,\(B_j\)的最小值是否小于\(-B_i\)

这个可以用平衡树或权值线段树来维护

再算上二分、点分治的时间复杂度,总时间复杂度使\(\Theta(n\space log^3 n)\)的,看上去有点悬

考虑加一些小优化,比如:

1.预处理点分树,就不用二分时每次判断都求一遍重心;

2.当找到一条合法的链后,立刻退出;

3.没有必要把当前区域的重心的最后一个儿子的子树里的点的信息加入平衡树或权值线段树

...

然而还是跑得很慢…

#include<algorithm>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define maxn 50010
#define maxm (maxn<<1)
#define rep(i,x,y) for(int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(int i=(x);i>=(y);--i)
#define ls son[u][0]
#define rs son[u][1]
#define eps 5e-3
#define LD long double
using namespace std;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')ch=getchar(),f=-1;
while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*f;
}
const double inf=(1.0/0.0);
double mx[maxn],key[maxn],key2[maxn],dep[maxn],dep2[maxn],w[maxm],K,L,R,mid,ans;
int n,fa[maxn],son[maxn][2],rt,vis[maxn],ww[maxn],siz[maxn],nowsiz,mnsiz,wt,nxt[maxm],fir[maxn],v[maxm],cnt,nd,yes;
int nt[maxn],vv[maxn],fs[maxn],cnt2,root;
void ade(int u1,int v1,double w1){v[cnt]=v1,nxt[cnt]=fir[u1],w[cnt]=w1,fir[u1]=cnt++;}
void ade2(int u1,int v1){vv[cnt2]=v1,nt[cnt2]=fs[u1],fs[u1]=cnt2++;}
void getsiz(int u,int fa)
{
siz[u]=1;int nowmx=0;
for(int k=fir[u];k!=-1;k=nxt[k])
if(v[k]!=fa&&!vis[v[k]])getsiz(v[k],u),siz[u]+=siz[v[k]],nowmx=max(nowmx,siz[v[k]]);
nowmx=max(nowmx,nowsiz-siz[u]);
if(nowmx<mnsiz)mnsiz=nowmx,wt=u;
}
void getwt(int u,int fa,int sumsiz)
{
nowsiz=sumsiz,mnsiz=n+1,getsiz(u,0),vis[wt]=1;
int now=wt;
if(sumsiz==n)root=now;
else ade2(fa,now);
for(int k=fir[now];k!=-1;k=nxt[k])
if(!vis[v[k]])getwt(v[k],now,siz[v[k]]>siz[now]?sumsiz-siz[now]:siz[v[k]]);
}
void pu(int u)
{
if(!u)return;
mx[u]=key2[u];
if(ls)mx[u]=min(mx[u],mx[ls]);
if(rs)mx[u]=min(mx[u],mx[rs]);
return;
}
int getso(int u){return son[fa[u]][0]!=u;}
void rot(int u)
{
register int fu=fa[u],ffu=fa[fu],l=getso(u),fl=getso(fu),r=l^1,rson=son[u][r];
if(ffu)son[ffu][fl]=u;son[u][r]=fu,son[fu][l]=rson;if(rson)fa[rson]=fu;fa[u]=ffu,fa[fu]=u;
pu(fu),pu(u);
}
void ins(double x,double y)
{
register int u=rt,lst=0,to;
while(u&&key[u]!=x)lst=u,to=x>key[u]?1:0,u=son[u][to];
if(!u)
{
u=++nd,ls=rs=0,key[u]=x,key2[u]=y,mx[u]=y,ww[u]=rand()*rand()%63427919,fa[u]=lst;
if(lst)son[lst][to]=u/*,upd2(lst)*/;
else rt=u;
while(fa[u]&&ww[fa[u]]>ww[u])rot(u);
if(!fa[u])rt=u;
}
else {key2[u]=min(key2[u],y),mx[u]=min(mx[u],y);while(u)pu(u),u=fa[u];}return;
}
double ask(double x)
{
int u=rt;double res=inf;
while(u)
{
if(x<=key[u]){res=min(res,min(key2[u],rs?mx[rs]:inf));u=ls;}
else u=rs;
}
return res;
}
void asky(int u,int fa)
{
double res=ask(-dep[u]);
if(res!=inf){if(res+dep2[u]<=0){yes=1;return;}}
for(int k=fir[u];k!=-1;k=nxt[k])
if(!vis[v[k]]&&v[k]!=fa)
{
dep[v[k]]=dep[u]+w[k]+mid,dep2[v[k]]=dep2[u]+w[k]-mid,asky(v[k],u);
if(yes)return;
}
}
void addy(int u,int fa)
{
ins(dep[u],dep2[u]);
for(int k=fir[u];k!=-1;k=nxt[k])
if(!vis[v[k]]&&v[k]!=fa)addy(v[k],u);
}
void reset(){rt=0;nd=0,mx[0]=inf;}
void gety(int now)
{
reset();
ins(0,0);
vis[now]=1;
int lst=0;
for(int k=fir[now];k!=-1;k=nxt[k])if(!vis[v[k]])lst=v[k];
for(int k=fir[now];k!=-1;k=nxt[k])
{
if(!vis[v[k]])
{
dep[v[k]]=w[k]+mid,dep2[v[k]]=w[k]-mid;
asky(v[k],now);
if(yes)return;
if(v[k]!=lst)addy(v[k],now);
}
}
for(int k=fs[now];k!=-1;k=nt[k])
{gety(vv[k]);if(yes)return;}
}
int main()
{
srand(time(0));
nowsiz=n=read();scanf("%lf",&K);
memset(fir,-1,sizeof(fir));
memset(fs,-1,sizeof(fs));
rep(i,1,n-1){int x=read(),y=read();double z;scanf("%lf",&z);R=max(R,z-K<0.0?K-z:z-K),ade(x,y,z-K),ade(y,x,z-K);}
getwt(1,0,n);
ans=R;
while(R-L>=eps)
{
mid=(R+L)/2.0;yes=0;
rep(i,1,n)vis[i]=0;
gety(root);
if(yes)ans=min(ans,mid),R=mid;
else L=mid;
}
printf("%.0lf",floor(ans));
return 0;
}

并不对劲的uoj276. [清华集训2016]汽水的更多相关文章

  1. UOJ276 [清华集训2016] 汽水 【二分答案】【点分治】【树状数组】

    题目分析: 这种乱七八糟的题目一看就是点分治,答案有单调性,所以还可以二分答案. 我们每次二分的时候考虑答案会不会大于等于某个值,注意到系数$k$是无意义的,因为我们可以通过转化使得$k=0$. 合并 ...

  2. BZOJ.4738.[清华集训2016]汽水(点分治 分数规划)

    BZOJ UOJ 记\(val_i\)是每条边的边权,\(s\)是边权和,\(t\)是经过边数,\(k\)是给定的\(k\). 在点分治的时候二分答案\(x\),设\(|\frac st-k|=x\) ...

  3. [UOJ#276][清华集训2016]汽水[分数规划+点分治]

    题意 给定一棵 \(n\) 个点的树,给定 \(k\) ,求 \(|\frac{\sum w(路径长度)}{t(路径边数)}-k|\)的最小值. \(n\leq 5\times 10^5,k\leq ...

  4. [UOJ#276]【清华集训2016】汽水

    [UOJ#276][清华集训2016]汽水 试题描述 牛牛来到了一个盛产汽水的国度旅行. 这个国度的地图上有 \(n\) 个城市,这些城市之间用 \(n−1\) 条道路连接,任意两个城市之间,都存在一 ...

  5. UOJ #274. 【清华集训2016】温暖会指引我们前行 [lct]

    #274. [清华集训2016]温暖会指引我们前行 题意比较巧妙 裸lct维护最大生成树 #include <iostream> #include <cstdio> #incl ...

  6. UOJ_274_[清华集训2016]温暖会指引我们前行_LCT

    UOJ_274_[清华集训2016]温暖会指引我们前行_LCT 任务描述:http://uoj.ac/problem/274 本题中的字典序不同在于空串的字典序最大. 并且题中要求排序后字典序最大. ...

  7. UOJ 275. 【清华集训2016】组合数问题

    UOJ 275. [清华集训2016]组合数问题 组合数 $C_n^m $表示的是从 \(n\) 个物品中选出 \(m\) 个物品的方案数.举个例子,从$ (1,2,3)(1,2,3)$ 三个物品中选 ...

  8. UOJ #269. 【清华集训2016】如何优雅地求和

    UOJ #269. [清华集训2016]如何优雅地求和 题目链接 给定一个\(m\)次多项式\(f(x)\)的\(m+1\)个点值:\(f(0)\)到\(f(m)\). 然后求: \[ Q(f,n,x ...

  9. 【UOJ274】【清华集训2016】温暖会指引我们前行 LCT

    [UOJ274][清华集训2016]温暖会指引我们前行 任务描述 虽然小R住的宿舍楼早已来了暖气,但是由于某些原因,宿舍楼中的某些窗户仍然开着(例如厕所的窗户),这就使得宿舍楼中有一些路上的温度还是很 ...

随机推荐

  1. Leetcode 273.整数转换英文表示

    整数转换英文表示 将非负整数转换为其对应的英文表示.可以保证给定输入小于 231 - 1 . 示例 1: 输入: 123 输出: "One Hundred Twenty Three" ...

  2. Laya 利用JS进行反射

    Laya 利用JS进行反射 @author ixenos 当需要配表调用函数时,可以利用js的eval来调用 1.在配置js中写下: function callAsFunc(funcName){ ev ...

  3. C#通信学习(一)

    基础知识 TCP/IP:Transmission Control Protocol/Internet Protocol,传输控制协议/因特网互联协议,又名网络通讯协议.简单来说:TCP控制传输数据,负 ...

  4. HDU1280前m大的数creat at 9:51,3.13,2016

    前m大的数 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Subm ...

  5. 如何在非localhost情况下访问Istio中的服务UI

    在使用Istio时经常会遇到需要用localhost访问服务UI才能看到相关的一些数据 但对于远程连接的时候使用localhost并不方便,所以需要修改一下它的部署文件,将原先的cluster IP改 ...

  6. git clone, push, pull, fetch 的用法

    Git是目前最流行的版本管理系统,学会Git几乎成了开发者的必备技能. Git有很多优势,其中之一就是远程操作非常简便.本文详细介绍5个Git命令,它们的概念和用法,理解了这些内容,你就会完全掌握Gi ...

  7. POJ2455 Secret Milking Machine【二分,最大流】

    题目大意:N个点P条边,令存在T条从1到N的路径,求路径上的边权的最大值最小为多少 思路:做了好多二分+最大流的题了,思路很好出 二分出最大边权后建图,跑dinic 问题是....这题是卡常数的好题! ...

  8. android去除标题栏和状态栏(全屏)

    转--http://www.eoeandroid.com/thread-66555-1-1.html 在开发中我们经常需要把我们的应用设置为全屏,这里我所知道的有俩中方法,一中是在代码中设置,另一种方 ...

  9. 【HDOJ6342】Expression in Memories(模拟)

    题意: 给定一个由0123456789+* ?组成的表达式,其中?可以被改为任意其它字符,问修改问号后是否有方案使得表达式合法 len<=5e2,sumlen<=1e5 思路: #incl ...

  10. 给你两个字符串str1,str2,找出str2在str1中的位置

    如题 题目参考链接: http://blog.csdn.net/hxz_qlh/article/details/14110221 代码来自非原创 #include <iostream> # ...