UOJ276 [清华集训2016] 汽水 【二分答案】【点分治】【树状数组】
题目分析:
这种乱七八糟的题目一看就是点分治,答案有单调性,所以还可以二分答案。
我们每次二分的时候考虑答案会不会大于等于某个值,注意到系数$k$是无意义的,因为我们可以通过转化使得$k=0$。
合并的过程相当于很多个向量,加起来后看斜率。
注意单个向量也要判定。
由于有了二分的答案$Ans$。判定变得简单多了,推一下。
令$(A,C)$是从一个点到重心的一个向量,$(B,D)$是从另一个点到重心的向量。其中$A$和$B$是重心到该点的路径权值和,$C$和$D$是经过的边数。
$-k \leq \frac{A+C}{B+D} \leq k \Rightarrow -k(B+D) \leq A+C \leq k(B+D)$.
进一步的$A+kB \geq -C-kD$且$A-kB \leq kD-C$。虽然有四元,但是顺序相互关联,所以实际只有两元,排序后树状数组就可以解决啦。
#include<bits/stdc++.h>
using namespace std; typedef long long ll; const int maxn = ; ll k,md; int flag = ,num,n,rnum;
vector <pair<int,ll> > g[maxn];
int arr[maxn],sz[maxn],imp[maxn],cnt[maxn];
struct node{ll A;int B,pla;}op[maxn]; int cmp(node X,node Y){
return -X.A-md*X.B < -Y.A-md*Y.B;
} struct Fenwick{
int C[maxn];
void Add(int now){
while(now <= rnum){C[now] ++; now += (now&-now);}
}
int query(int now){
int ans = ;
while(now){ans += C[now]; now -= (now&-now);}
return ans;
}
}T1; void read(){
scanf("%d%lld",&n,&k);
for(int i=;i<n;i++){
int x,y;long long v; scanf("%d%d%lld",&x,&y,&v); v -= k;
g[x].push_back(make_pair(y,v)); g[y].push_back(make_pair(x,v));
}
} void dfs1(int now,int fa,int dp){
sz[now] = ;imp[now] = ;
for(auto it : g[now]){
if((arr[it.first] && arr[it.first] < dp) || fa == it.first) continue;
dfs1(it.first,now,dp); sz[now] += sz[it.first];
}
} int dfs2(int now,int fa,int dp,int ssz){
int ans = ;
for(auto it : g[now]){
if((arr[it.first] && arr[it.first] < dp) || fa == it.first) continue;
int data = dfs2(it.first,now,dp,ssz);
if(ans== || imp[ans] > imp[data])ans = data;
imp[now] = max(sz[it.first],imp[now]);
}
imp[now] = max(imp[now],ssz-sz[now]);
if(ans== || imp[ans] > imp[now]) ans = now;
return ans;
} void dfs3(int now,int fa,int dp,int A,int B){
for(auto it : g[now]){
if(it.first == fa || (arr[it.first] && arr[it.first] < dp)) continue;
op[++num] = (node){A+it.second,B+,it.first};
dfs3(it.first,now,dp,A+it.second,B+);
}
} long long lisan[maxn];
void solve(int dr){
rnum = num;
for(int i=;i<=num;i++){lisan[i] = -op[i].A+md*op[i].B;}
sort(lisan+,lisan+num+);rnum = unique(lisan+,lisan+num+)-lisan-;
for(int i=;i<=rnum;i++) T1.C[i]=;
for(int i=num,j=;i>=;i--){
while(j <= num && (-op[j].A-md*op[j].B < op[i].A+md*op[i].B)){
T1.Add(lower_bound(lisan+,lisan+rnum+,-op[j].A+md*op[j].B)-lisan);
j++;
}
int ans=j--T1.query(upper_bound(lisan+,lisan+rnum+,op[i].A-md*op[i].B)-lisan-);
if(op[i].A-md*op[i].B < -op[i].A+md*op[i].B && j > i)ans--;
if(dr == ){
if(ans - cnt[op[i].pla]){flag = ;return;}
}else{cnt[op[i].pla] = ans;}
}
} void divide(int now,int dp,int lst,long long AA){
dfs1(now,,dp); int heavy = dfs2(now,,dp,sz[now]);arr[heavy] = dp;
for(auto it : g[heavy]){
if(arr[it.first]&&arr[it.first]<dp) continue;
divide(it.first,dp+,heavy,it.second);
if(flag == ) return;
}
num = ; dfs3(heavy,,dp,,); sort(op+,op+num+,cmp);
solve(); num = ;
if(lst) {
num = ;dfs3(now,,dp,AA,);
sort(op+,op+num+,cmp);
for(int i=;i<=num;i++) cnt[op[i].pla] = ;
solve();
}
} void work(){
long long l = ,r = 1e13;
while(l < r){
md = (l+r)/; flag = ;
memset(arr,,sizeof(arr));
divide(,,,);
if(flag) r = md; else l = md+;
}
printf("%lld",l-);
} int main(){
read();
work();
return ;
}
UOJ276 [清华集训2016] 汽水 【二分答案】【点分治】【树状数组】的更多相关文章
- 并不对劲的uoj276. [清华集训2016]汽水
想要很对劲的讲解,请点击这里 题目大意 有一棵\(n\)(\(n\leq 50000\))个节点的树,有边权 求一条路径使该路径的边权平均值最接近给出的一个数\(k\) 输出边权平均值下取整的整数部分 ...
- [UOJ#276][清华集训2016]汽水[分数规划+点分治]
题意 给定一棵 \(n\) 个点的树,给定 \(k\) ,求 \(|\frac{\sum w(路径长度)}{t(路径边数)}-k|\)的最小值. \(n\leq 5\times 10^5,k\leq ...
- BZOJ5321 JXOI2017加法(二分答案+贪心+堆+树状数组)
二分答案后得到每个位置需要被加的次数.考虑贪心.从左到右考虑每个位置,将以该位置为左端点的区间按右端点从大到小加进堆.看该位置还需要被加多少次,如果不需要加了就不管,否则取堆顶区间将其选择,BIT实现 ...
- [bzoj4009] [HNOI2015]接水果 整体二分+扫描线+dfs序+树状数组
Description 风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果. 由于她已经DT FC 了The big black, 她觉得这个游戏太简单了,于是发明了一个更 加 ...
- 洛谷P1527 [国家集训队] 矩阵乘法 [整体二分,二维树状数组]
题目传送门 矩阵乘法 题目描述 给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数. 输入输出格式 输入格式: 第一行两个数N,Q,表示矩阵大小和询问组数: 接下来N行N列一共N* ...
- csp-s模拟测试56(10.2)Merchant「二分」·Equation「树状数组」
又死了......T1 Merchant 因为每个集合都可以写成一次函数的形式,所以假设是单调升的函数,那么随着t越大就越佳 而单调减的函数,随着t的增大结果越小,所以不是单调的??? 但是我们的单调 ...
- BZOJ.4738.[清华集训2016]汽水(点分治 分数规划)
BZOJ UOJ 记\(val_i\)是每条边的边权,\(s\)是边权和,\(t\)是经过边数,\(k\)是给定的\(k\). 在点分治的时候二分答案\(x\),设\(|\frac st-k|=x\) ...
- UOJ#276. 【清华集训2016】汽水 二分答案 点分治
原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ276.html 题解 首先,读入的时候就将所有的 $w_i$ 减掉 $k$ . 于是我们要求的就是平均值最 ...
- HDU 5877 2016大连网络赛 Weak Pair(树状数组,线段树,动态开点,启发式合并,可持久化线段树)
Weak Pair Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others) Tota ...
随机推荐
- 最新版XCoder 的使用方法
1.项目中,新建一个类库.名字随意,我取名:XCoder 2.右键 > 管理nuget程序包:搜索 XCode 并安装 3.在项目中新建:data.project.xml 的xml文件,并写入数 ...
- urllib爬虫(流程+案例)
网络爬虫是一种按照一定规则自动抓取万维网信息的程序.在如今网络发展,信息爆炸的时代,信息的处理变得尤为重要.而这之前就需要获取到数据.有关爬虫的概念可以到网上查看详细的说明,今天在这里介绍一下使用ur ...
- netty同端口监听tcp和websocket协议
前言: 软件通信七层结构(osi模型)中由协议套协议最终组成最高级应用层协议(http等等),下三层结构偏向与数据通信,上三层更偏向于数据处理,中间的传输层则是连接上三层与下三层之间的桥梁,每一层都做 ...
- Django的model form组件
前言 首先对于form组件通过全面的博客介绍,对于form我们应该知道了它的大致用法,这里我们需要明确的一点是,我们定义的form与model其实没有什么关系,只是在逻辑上定义form的时候字段名期的 ...
- Dockerfile centos7_php5.6.36
Dockerfile: FROM centos:7 MAINTAINER www.ctnrs.com RUN yum install epel-release -y && \ yum ...
- 14-Requests+正则表达式爬取猫眼电影
'''Requests+正则表达式爬取猫眼电影TOP100''''''流程框架:抓去单页内容:利用requests请求目标站点,得到单个网页HTML代码,返回结果.正则表达式分析:根据HTML代码分析 ...
- Codeforces Round #533 (Div. 2) A. Salem and Sticks(暴力)
A. Salem and Sticks time limit per test 1 second memory limit per test 256 megabytes input standard ...
- 关于php,python,javascript文件或者模块导入引入的区别和联系
前言: 我们经常看到编程语言之间,文件或者模块的引来引去的,但是他们在各个编程语言之间有什么区别和联系呢? 1.javascript (1).全局引入方式: <script src='xxxxx ...
- WinRAR从入门到高级的操作技巧集合
一.基础技巧 1.批量建立文件夹 如果在工作中,经常要建立很多相同文件夹结构(如在备份数据时).那可以把这个繁琐的工作让WinRAR完成:先在“资源管理器”中把多个文件夹结构建好(包括其下的子文件夹) ...
- dynamo与cassandra区别
虽说cassandra是dynamo的开源版本,但两者还是有很大区别的. coordinator的选取: 在dynamo论文中,一般是preference list中N个副本的第一个 为什么叫“一般” ...