为什么你们常数都这么小啊

UOJ #276

题意:在树上找一条链使得|边权平均值$ -k$|尽量小,$ n<=5e4$


$ Solution:$

首先二分答案$ ans$,即我们需要找一条链使得边权平均值 $\in [-ans,ans]$

我们分正负两半分开讨论

先假设平均值$ \in (0,ans]$

将原树点分

统计过根的所有链

将这些链记录长度$len$,边数$sum$,所属子树标号$id$之后按长度排序

添加一条链$(0,0,0)$,则过某点的链一定是某两条不在同一子树的链拼接而成

两条链拼接合法当且仅当$ \frac{len_i+len_j}{sum_i+sum_j} \in (0,ans]$

化简得$ len_i+len_j>0且len_i-ans·sum_i+len_j-ans·sum_j \leq 0$

我们记录后缀$ len_i-ans·sum_i$的最小值

然后两个指针扫扫就好了

注意存在不在同一子树的限制,我们需要同时记录不在同一子树的后缀最小值和次小值,这样才能合并

如果平均值$ \in [-ans,0]$,也用同样的方法维护前缀最大值和次大值即可

注意各种边界的问题

时间复杂度:$ O(n \ log \ n \ log \ val)$


$ my \ code$

#include<ctime>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#define M 100010
#define rt register int
#define ll long long
using namespace std;
inline ll read(){
ll x = ; char zf = ; char ch = getchar();
while (ch != '-' && !isdigit(ch)) ch = getchar();
if (ch == '-') zf = -, ch = getchar();
while (isdigit(ch)) x = x * + ch - '', ch = getchar(); return x * zf;
}
void write(ll y){if(y<)putchar('-'),y=-y;if(y>)write(y/);putchar(y%+);}
void writeln(const ll y){write(y);putchar('\n');}
int i,j,k,m,n,x,y,z,cnt,all,Root,nowmin;
int F[M],L[M],N[M],a[M],size[M];ll c[M];
bool vis[M];
void add(int x,int y,ll z){
a[++k]=y;c[k]=z;
if(!F[x])F[x]=k;
else N[L[x]]=k;
L[x]=k;
}
void getRoot(int x,int pre){
size[x]=;int Maxsize=;
for(rt i=F[x];i;i=N[i])if(a[i]!=pre&&!vis[a[i]]){
getRoot(a[i],x);size[x]+=size[a[i]];
Maxsize=max(Maxsize,size[a[i]]);
}
Maxsize=max(Maxsize,all-size[x]);
if(Maxsize<nowmin)nowmin=Maxsize,Root=x;
}
int cs;
vector<int>e[];
void build(int x){
int ls=all;vis[x]=;
for(rt i=F[x];i;i=N[i])if(!vis[a[i]]){
all=(size[a[i]]>size[x]?ls-size[x]:size[a[i]]);
nowmin=;Root=;getRoot(a[i],x);
e[x].push_back(Root);
build(Root);
}
}
struct chain{
ll len;int sl,col;
bool operator <(const chain s)const{
return len<s.len;
}
}q[];int t;
void Add(int col,int x,int pre,ll len,int sl){
q[++t]={len,sl,col};
for(rt i=F[x];i;i=N[i])if(a[i]!=pre&&!vis[a[i]])Add(col,a[i],x,len+c[i],sl+);
}
int qzmax[][],hzmin[][],allsize=;
bool check(int x,ll ans){//0...x
q[t=]={,,};vis[x]=;
for(rt i=F[x];i;i=N[i])if(!vis[a[i]])Add(a[i],a[i],x,c[i],);
sort(q+,q+t+);
qzmax[][]=;qzmax[][]=;
for(rt i=;i<=t;i++){
int id0=qzmax[i-][],id1=qzmax[i-][];
qzmax[i][]=id0;qzmax[i][]=id1;
if(q[i].len+ans*q[i].sl>q[id0].len+ans*q[id0].sl){
if(q[i].col!=q[id0].col)qzmax[i][]=qzmax[i][];
qzmax[i][]=i;
}
else if(q[i].len+ans*q[i].sl>q[id1].len+ans*q[id1].sl||!id1){
if(q[i].col!=q[id0].col)qzmax[i][]=i;
}
}
hzmin[t][]=t;hzmin[t][]=;
for(rt i=t-;i>=;i--){
int id0=hzmin[i+][],id1=hzmin[i+][];
hzmin[i][]=id0;hzmin[i][]=id1;
if(q[i].len-ans*q[i].sl<q[id0].len-ans*q[id0].sl){
if(q[i].col!=q[id0].col)hzmin[i][]=hzmin[i][];
hzmin[i][]=i;
}
else if(q[i].len-ans*q[i].sl<q[id1].len-ans*q[id1].sl||!id1){
if(q[i].col!=q[id0].col)hzmin[i][]=i;
}
}
int R=t;
for(rt i=;i<=t;i++){
while((q[i].len+q[R].len>||R==i)&&R)R--;
if(R==)break;if(R>=i)continue;
int maxv=qzmax[R][];
if(q[qzmax[R][]].col==q[i].col)maxv=qzmax[R][];
if(maxv==)continue;
if(q[i].len+q[i].sl*ans+q[maxv].len+ans*q[maxv].sl>)return ;
}
int L=;
for(rt i=t;i>=;i--){
while((q[i].len+q[L].len<||L==i)&&L<=t)L++;
if(L>t)break;if(L<=i)continue;
int minv=hzmin[L][];
if(q[hzmin[L][]].col==q[i].col)minv=hzmin[L][];
if(!minv)continue;
if(q[i].len-q[i].sl*ans+q[minv].len-ans*q[minv].sl<)return ;
}
bool res=;
for(rt i=;i<e[x].size();i++)if(!res)res|=check(e[x][i],ans);
return res;
}
int main(){
n=read();ll w=read();
for(rt i=;i<n;i++){
x=read();y=read();ll z=read();
add(x,y,z-w);
add(y,x,z-w);
}
nowmin=;all=n;getRoot(,);
int troot=Root;build(Root);
memset(vis,,sizeof(vis));
ll L=,R=;
while(L<=R){
memset(vis,,sizeof(vis));
ll mid=(L+R)/;
if(check(troot,mid))R=mid-;
else L=mid+;
}
write(R);
return ;
}

UOJ #276「清华集训2016」汽水的更多相关文章

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

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

  2. UOJ#276. 【清华集训2016】汽水 二分答案 点分治

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ276.html 题解 首先,读入的时候就将所有的 $w_i$ 减掉 $k$ . 于是我们要求的就是平均值最 ...

  3. uoj#276. 【清华集训2016】汽水(分数规划+点分治)

    传送门 没想到点分治那一层-- 首先不难发现这是个分数规划,先把所有的边长减去\(k\),二分答案,设为\(mid\),就是要求路径平均值\(ans\in[-mid,mid]\) 先来考虑\(ans\ ...

  4. UOJ #36「清华集训2014」玛里苟斯

    这怎么想得到啊......... UOJ #36 题意:求随机一个集合的子集的异或和的$k$次方的期望值,保证答案$ \lt 2^{63},1 \leq k \leq 5$ $ Solution:$ ...

  5. UOJ #2321. 「清华集训 2017」无限之环

    首先裂点表示四个方向 一条边上都有插头或者都不有插头,相当于满足流量平衡 最大流 = 插头个数*2时有解 然后求最小费用最大流 黑白染色分别连原点汇点

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

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

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

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

  8. Loj #2331. 「清华集训 2017」某位歌姬的故事

    Loj #2331. 「清华集训 2017」某位歌姬的故事 IA 是一名会唱歌的女孩子. IOI2018 就要来了,IA 决定给参赛选手们写一首歌,以表达美好的祝愿.这首歌一共有 \(n\) 个音符, ...

  9. Loj #2324. 「清华集训 2017」小 Y 和二叉树

    Loj #2324. 「清华集训 2017」小 Y 和二叉树 小Y是一个心灵手巧的OIer,她有许多二叉树模型. 小Y的二叉树模型中,每个结点都具有一个编号,小Y把她最喜欢的一个二叉树模型挂在了墙上, ...

随机推荐

  1. Python模块之time、random、os、sys、序列化、re

    Time模块 和时间有关系的我们就要用到时间模块.在使用模块之前,应该首先导入这个模块. #常用方法 1.time.sleep(secs) (线程)推迟指定的时间运行.单位为秒. 2.time.tim ...

  2. java 中 byte[]、File、InputStream 互相转换

    1.将File.FileInputStream 转换为byte数组: File file = new File("test.txt"); InputStream input = n ...

  3. jsr223 md5

    import java.security.MessageDigest; String content = "xxx"; MessageDigest digest = Message ...

  4. 信用评分卡 (part 6 of 7)

    python信用评分卡(附代码,博主录制) https://study.163.com/course/introduction.htm?courseId=1005214003&utm_camp ...

  5. kubernetes1.5.2 dashboard配置

    镜像:https://hub.daocloud.io/#!/repos/f8919a2c-2540-424e-8758-d23cc76b6d80 启动Kubernetes集群 配置Kubernetes ...

  6. Python中字符串的操作

    字符串的基本详情 用单引号或者双引号包含的内容 不支持直接在内存中修改 可支持索引.切片.成员检查.长度查看 字符串赋值到变量 str1 = 'hello world' 字符串打印查看 str1 = ...

  7. 【JS】js将 /Date(1518943415760+0800)/ 转换为2018-2-18 16:43:35格式

    function formatDate(dt) { var year = dt.getFullYear(); var month = dt.getMonth() + 1; var date = dt. ...

  8. 获取spring上下文的bean 工具类

    有些场景我们不属于controller,service,dao,但是我们需要从spring中得到spring容器里面的bean.这时候我们需要一个类继承 ApplicationContextAware ...

  9. Linux学习笔记:【000】Linux系统入门

    什么是Linux? Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX(可移植操作系统接口 Portable Operating System Interface of UN ...

  10. TPS和QPS的区别和理解【转】

    QPS:Queries Per Second意思是“每秒查询率”,是一台服务器每秒能够相应的查询次数,是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准. TPS:是Transactions ...