【LOJ6620】「THUPC 2019」不等式 / inequality(线段树)
大致题意: 给你两个长度为\(n\)的数组\(a_i\)和\(b_i\),定义\(f_k(x)=\sum_{i=1}^k|a_ix+b_i|\),对于\(k=1\sim n\)的每个\(f_k\),求\(f_k\)的最小值。
前言
懒得写平衡树,于是就想了个线段树做法。
还有,题目没有特殊说明不存在\(a_i=0\)的情况,但数据中确实不存在这样的情况,我的做法遇上这种情况可能要加一些特殊处理,然而我懒得写了。
前置知识
先考虑一个简单的问题:
\(Problem\ 1\):
给你一个长度为\(n\)的数组\(b_i\),求\(\sum_{i=1}^n|x+b_i|\)的最小值。
显然根据初中数学可知,当\(x\)取\(b_i\)的中位数的相反数时,这个式子取最小值。
再考虑一个升级版的问题:
\(Problem\ 2\):
给你两个长度为\(n\)的数组\(a_i\)和\(b_i\),求\(\sum_{i=1}^n|a_ix+b_i|\)的最小值。(假定任意\(a_i>0\))
这看似复杂,实际上不难发现,\(|a_ix+b_i|=a_i|x+\frac{a_i}{b_i}|\),也就是一个\(|a_ix+b_i|\)可以拆成\(a_i\)个\(|x+\frac{a_i}{b_i}|\)。
然后按上面\(Problem\ 1\)的方法做即可。
虽说上面我们假定\(a_i>0\),但实际上对于\(a_i<0\)的情况,我们可以同时将\(a_i\)和\(b_i\)变为其相反数,这样就能满足\(a_i>0\)了。
前置处理
我们可以发现,这道题要我们做的,其实就是每次加入一组\(a_i\)和\(b_i\),维护\(Problem\ 2\)的答案。
假如我们把\(|a_ix+b_i|\)拆成\(a_i\)个\(|x+\frac{a_i}{b_i}|\),由于\(a_i<10^5\),显然最后数的个数的规模是难以接受的。
但如果我们能够开一个数组\(p\),以\(\frac{a_i}{b_i}\)为下标,那么我们实际上每次只要把\(p_{\frac{a_i}{b_i}}\)加上\(a_i\)就能很方便地维护数组。
可是,以一个实数为下标显然是不可能的。因此,我们就需要在处理询问前先将\(\frac{a_i}{b_i}\)给离散化。
注意,为了防止挂精度,推荐在排序比较分数大小时可以先交叉相乘再比较,避免出现除法。
线段树
设我们求出中位数的值是\(e\),且其在离散化后的值是\(k\),那么答案就是:
\]
其中\(Fact_i\)表示\(i\)所表示的真实值。
则我们需要一个数据结构,能够实现四种操作:单点修改、求中位数、求区间\(\sum p_i\)和求区间\(\sum p_i\times Fact_i\)。
于是我们就想到线段树。
注意求区间\(\sum p_i\times Fact_i\)看似棘手,但由于我们是单点修改,因此我们只要对于每个位置维护两个值即可。
特殊地,根据先前定义我们可知,每次加入一组\(a_i,b_i\),设\(t\)为\(\frac {b_i}{a_i}\)离散化后的值,那么我们会将\(p_{t}\)加上\(a_i\),那么\(p_t\times Fact_t\)其实就是加上了\(a_i\times Fact_t=a_i\times \frac{b_i}{a_i}=b_i\)。
而对于求中位数,其实我们如果维护\(g=\sum p_i\),那么中位数就是第\(\lfloor\frac{g+1}2\rfloor\)个数。
然后,我们在线段树上二分,便可以找到中位数离散化后的值\(k\),进而就可以得到\(e\)了。
至于具体实现,可见代码。
代码
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 500000
#define LL long long
#define DB double
#define abs(x) ((x)<0?-(x):(x))
using namespace std;
int n,a[N+5],b[N+5],s[N+5],p[N+5];
I bool cmp(CI x,CI y) {return 1LL*b[x]*a[y]<1LL*b[y]*a[x];}
class FastIO
{
private:
#define FS 100000
#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
#define tn (x<<3)+(x<<1)
#define D isdigit(c=tc())
int f;char c,*A,*B,FI[FS];
public:
I FastIO() {A=B=FI;}
Tp I void read(Ty& x) {x=0,f=1;W(!D) f=c^'-'?1:-1;W(x=tn+(c&15),D);x*=f;}
}F;
class SegmentTree//线段树
{
private:
#define PT CI l=1,CI r=n,CI rt=1
#define LT l,mid,rt<<1
#define RT mid+1,r,rt<<1|1
#define PU(x) (T[x]=T[x<<1]+T[x<<1|1],S[x]=S[x<<1]+S[x<<1|1])
LL T[N<<2],S[N<<2];
public:
I void Upt(CI x,Con LL& y,Con LL& z,PT)//单点修改
{
if(l==r) return (void)(T[rt]+=y,S[rt]+=z);int mid=l+r>>1;
x<=mid?Upt(x,y,z,LT):Upt(x,y,z,RT),PU(rt);
}
I int Qmid(Con LL& rk,PT)//求中位数
{
if(l==r) return l;int mid=l+r>>1;
return rk<=T[rt<<1]?Qmid(rk,LT):Qmid(rk-T[rt<<1],RT);
}
I LL Qtot(CI x,CI y,PT)//区间求和1
{
if(x<=l&&r<=y) return T[rt];int mid=l+r>>1;
return (x<=mid?Qtot(x,y,LT):0)+(y>mid?Qtot(x,y,RT):0);
}
I LL Qsum(CI x,CI y,PT)//区间求和2
{
if(x<=l&&r<=y) return S[rt];int mid=l+r>>1;
return (x<=mid?Qsum(x,y,LT):0)+(y>mid?Qsum(x,y,RT):0);
}
}S;
int main()
{
RI i,k;LL g=0;DB e,w;for(F.read(n),i=1;i<=n;++i) F.read(a[i]);for(i=1;i<=n;++i) F.read(b[i]);//读入
for(i=1;i<=n;++i) a[i]<0&&(a[i]=-a[i],b[i]=-b[i]),s[i]=i;sort(s+1,s+n+1,cmp);//方便起见,将a[i]取正
for(k=0,i=1;i<=n;++i) (!k||(1LL*b[s[k]]*a[s[i]])^(1LL*b[s[i]]*a[s[k]]))&&(s[++k]=s[i]),p[s[i]]=k;//离散化,排序后去重
for(i=1;i<=n;++i)
{
S.Upt(p[i],a[i],b[i]),k=S.Qmid((g+=a[i])+1>>1),e=1.0*b[s[k]]/a[s[k]];//线段树上查询中位数
w=(e*S.Qtot(1,k)-S.Qsum(1,k))+(S.Qsum(k,n)-e*S.Qtot(k,n)),printf("%.8lf\n",w);//利用线段树查询所需信息计算答案
}return 0;
}
【LOJ6620】「THUPC 2019」不等式 / inequality(线段树)的更多相关文章
- 「THUPC 2019」不等式 / inequality
https://loj.ac/problem/6620 高中数学好题.. |kx+b|的函数图像很直观,直接考虑函数图像: 一定只有一段极小值点! 这个点就是最小值了 特点:斜率为0! 而且发现,如果 ...
- 【题解】#6622. 「THUPC 2019」找树 / findtree(Matrix Tree+FWT)
[题解]#6622. 「THUPC 2019」找树 / findtree(Matrix Tree+FWT) 之前做这道题不理解,有一点走火入魔了,甚至想要一本近世代数来看,然后通过人类智慧思考后发现, ...
- 「UNR#1」奇怪的线段树
「UNR#1」奇怪的线段树 一道好题,感觉解法非常自然. 首先我们只需要考虑一次染色最下面被包含的那些区间,因为把无解判掉以后只要染了一个节点,它的祖先也一定被染了.然后发现一次染色最下面的那些区间一 ...
- LOJ 2980 「THUSCH 2017」大魔法师——线段树
题目:https://loj.ac/problem/2980 线段树维护矩阵. 然后是 30 分.似乎是被卡常了?…… #include<cstdio> #include<cstri ...
- loj#2059. 「TJOI / HEOI2016」字符串 sam+线段树合并+倍增
题意:给你一个子串,m次询问,每次给你abcd,问你子串sa-b的所有子串和子串sc-d的最长公共前缀是多长 题解:首先要求两个子串的最长公共前缀就是把反过来插入变成最长公共后缀,两个节点在paren ...
- LOJ#3054. 「HNOI 2019」鱼
LOJ#3054. 「HNOI 2019」鱼 https://loj.ac/problem/3054 题意 平面上有n个点,问能组成几个六个点的鱼.(n<=1000) 分析 鱼题,劲啊. 容易想 ...
- #3146. 「APIO 2019」路灯
#3146. 「APIO 2019」路灯 题目描述 一辆自动驾驶的出租车正在 Innopolis 的街道上行驶.该街道上有 \(n + 1\) 个停车站点,它们将街道划分成了 \(n\) 条路段.每一 ...
- #3144. 「APIO 2019」奇怪装置
#3144. 「APIO 2019」奇怪装置 题目描述 考古学家发现古代文明留下了一种奇怪的装置.该装置包含两个屏幕,分别显示两个整数 \(x\) 和 \(y\). 经过研究,科学家对该装置得出了一个 ...
- 「WC 2019」数树
「WC 2019」数树 一道涨姿势的EGF好题,官方题解我并没有完全看懂,尝试用指数型生成函数和组合意义的角度推了一波.考场上只得了 44 分也暴露了我在数数的一些基本套路上的不足,后面的 \(\ex ...
随机推荐
- JS基础语法---String(字符串的案例)
练习1: var str = "我的宝宝最可爱,声音嗲嗲的"; var key = "可爱"; //先获取要截取的字符串的索引位置 var index = st ...
- 使用 Anydesk 5.1 TCP 通道(端口映射)功能从外网方便访问内网的 web/数据库等资源
Anydesk 5.1 带来一个新的功能:TCP 通道,在家办公时,通过互联网进行远程桌面连接到公司电脑,可以将家用电脑的某个端口,映射到公司网络的某个电脑( IP + 端口),不局限于被远程桌面连接 ...
- 产品经理如何使用 CODING 进行项目规划
CODING 为您的企业提供从概念到软件开发再到产品发布的全流程全周期软件研发管理,为您的研发团队提供全程助力,帮助研发团队捋清需求.不断迭代.快速反馈并能实时追踪项目进度直到完成.同时 CODING ...
- 28.分类算法---KNN
1.工作原理: 存在一个样本数据集合,也称为训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一数据与所属分类对应的关系.输入没有标签的数据后,将新数据中的每个特征与样本集中数据对应的特 ...
- (转)Ioc控制反转和依赖注入
转载地址:https://zhuanlan.zhihu.com/p/95869440 控制反转控制反转(Inversion of Control,简称IoC),是面向对象编程中的一种设计思想,其作用是 ...
- 网页前端之CSS学习记录总结篇
标签: 块级标签block:div, p, h1-h6, ul, ol,li, dl, dt, dd,table,tr等,独占一行,可以设置宽高,默认是父标签的100%:行内标签inline:a,sp ...
- BZOJ3894/LG4313 文理分科 新建点最小割
问题描述 BZOJ3894 LG4313 题解 显然一个人只能选文/理 -> 一个人只能属于文(S).理(T)集合中的一个 可以把选择文得到 \(art\) 的收益看做选择文失去 \(scien ...
- office2019专业版激活秘钥 激活码
office2019专业版激活码 激活秘钥 2019年5月更新 [Key]:F4QWT-NMMKH-XPTV9-W9HFB-B4JCQ [剩余次数:900000+] office2019激活 产品秘钥 ...
- 各种数和各种反演(所谓FFT的前置知识?)
每次问NC做多项式的题需要什么知识点. 各种数. 各种反演. 多项式全家桶. 然后我就一个一个地学知识点.然而还差好多,学到后面的前面的已经忘了(可能是我太菜吧不是谁都是NC啊) 然后发现每个知识点基 ...
- 01-Vue.js基础
一.Vue基础 1.介绍 Vue是一套用于构建用户界面的渐进式框架.Vue的核心库只关注视图层,不仅容易上手,还便于与第三方库或既有的项目整合.兼容性:Vue 不支持 IE8 及以下版本,因为 Vue ...