description
对于给定的
{
a
i
}
,
{
b
i
}
\{a_i\},\{b_i\}
{ai},{bi},定义
f
k
(
x
)
=
∑
i
=
1
k
abs
(
a
i
x
+
b
i
)
f_k(x)=\begin{matrix}\sum_{i=1}^k\end{matrix}\operatorname{abs}(a_ix+b_i)
fk(x)=∑i=1kabs(aix+bi)
对于每一个 k k k,求 f k ( x ) f_k(x) fk(x)的最小值
solution
首先考虑
a
i
=
1
a_i=1
ai=1的时候,也就是我们要求
min
{
∑
∣
x
+
b
i
∣
}
\min\{\sum |x+b_i|\}
min{∑∣x+bi∣}
∣
x
+
b
i
∣
|x+b_i|
∣x+bi∣的几何意义就是在数轴上,
x
x
x到
−
b
i
-b_i
−bi这个点的距离
那么根据初一数学的芝士,
x
x
x取所有
−
b
i
-b_i
−bi的时候可以取到最小值
那么当
a
i
=
−
1
a_i=-1
ai=−1的时候呢?每一个式子变成了
∣
−
x
+
b
i
∣
=
∣
x
−
b
i
∣
|-x+b_i|=|x-b_i|
∣−x+bi∣=∣x−bi∣,也就是数轴上
x
x
x到
b
i
b_i
bi的距离
这样的话我们还是把一个式子对应成了一个点
当
∣
a
i
∣
≠
1
|a_i|\neq1
∣ai∣=1时,也就是式子是最基本的
∣
a
i
x
+
b
i
∣
|a_ix+b_i|
∣aix+bi∣时,我们转化一下,变成
∣
a
i
∣
∣
x
+
b
i
a
i
∣
|a_i||x+\frac{b_i}{a_i}|
∣ai∣∣x+aibi∣,注意外面
a
i
a_i
ai的绝对值不能丢
这个式子相当于
a
i
a_i
ai倍的
x
x
x到
−
b
i
a
i
-\frac{b_i}{a_i}
−aibi的距离,相当于把它转化成了
a
i
a_i
ai个点
这样的话类比 a i = 1 a_i=1 ai=1的时候的方法,利用一个线段树维护这道题就轻松解决了
注意因为坐标可能出现分数,所以我们需要先算出每个式子转化成的坐标离散化之后再进行建树
细节还是挺多的,注意需要考虑 a i = 0 a_i=0 ai=0的情况
code
#include <bits/stdc++.h>
using namespace std;
# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)
# define int long long
# define double long double
const int N=1e6+5;
template<typename T> void read(T &x){
x=0;int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
x*=f;
}
int n;
int a[N],b[N];
double x[N],lsh[N];
int pos[N],tot,add;
struct node{
int l,r,cnt;
double sum;
}seg[N<<2];
# define lc (u<<1)
# define rc (u<<1|1)
void pushup(int u){
seg[u].cnt=seg[lc].cnt+seg[rc].cnt;
seg[u].sum=seg[lc].sum+seg[rc].sum;
}
void build(int u,int l,int r){
seg[u].l=l,seg[u].r=r;
if(l==r)return;
int mid=l+r>>1;
build(lc,l,mid);
build(rc,mid+1,r);
}
void update(int u,int x,int k,double xc){
if(seg[u].l==seg[u].r){
seg[u].cnt+=k;
seg[u].sum+=xc*k;
return;
}
int mid=seg[u].l+seg[u].r>>1;
if(x<=mid)update(lc,x,k,xc);
else update(rc,x,k,xc);
pushup(u);
}
int kth(int u,int k){
if(seg[u].l==seg[u].r)return seg[u].l;
if(seg[lc].cnt>=k)return kth(lc,k);
else return kth(rc,k-seg[lc].cnt);
}
int qcnt(int u,int l,int r){
if(l>r)return 0;
if(seg[u].l>=l&&seg[u].r<=r)return seg[u].cnt;
int mid=seg[u].l+seg[u].r>>1;
int res=0;
if(l<=mid)res+=qcnt(lc,l,r);
if(r>mid)res+=qcnt(rc,l,r);
return res;
}
double query(int u,int l,int r){
if(l>r)return 0;
if(seg[u].l>=l&&seg[u].r<=r)return seg[u].sum;
int mid=seg[u].l+seg[u].r>>1;
double res=0;
if(l<=mid)res+=query(lc,l,r);
if(r>mid)res+=query(rc,l,r);
return res;
}
signed main()
{
read(n);
Rep(i,1,n)read(a[i]);
Rep(i,1,n)read(b[i]);
Rep(i,1,n)x[i]=lsh[i]=-1.0*b[i]/a[i];
sort(lsh+1,lsh+n+1);
int sz=unique(lsh+1,lsh+n+1)-lsh-1;
Rep(i,1,n)pos[i]=lower_bound(lsh+1,lsh+sz+1,x[i])-lsh;
build(1,1,sz);
Rep(i,1,n){
if(!a[i])add+=abs(b[i]);
else update(1,pos[i],abs(a[i]),x[i]),tot+=abs(a[i]);
int to=kth(1,tot+1>>1);
printf("%Lf\n",(lsh[to]*qcnt(1,1,to-1)-query(1,1,to-1))+(query(1,to+1,sz)-lsh[to]*qcnt(1,to+1,sz))+add);
}
return 0;
}