CF1534G solution
前言: 1.管理员大大最仁慈善良可爱了对吧!(第4次了!求过!)
2.之前写这道题的时候看了很久题解才懂,所以自己又整理了一遍,本篇题解内容有不少借鉴洛谷题解区其它题解的,加上了自己的理解(解释了一下当时自己没看懂的地方),所以比较长(图都是自己画的哈哈)
3.如果蒟蒻讲错了,发现问题的神犇请教教我(谢谢!!)
思路:slope trick
一个点
考虑将点以
转移式:
为什么是这个范围,我们化简一下:
左式含义就是
而
带入右式得到
所以就是枚举所有在上一个点对应的直线上(过上一个点且斜率为
考虑
接下来我们考虑维护这个下凸壳。
取
如上图,黑色的是这个函数,所有红色标出的区间内的最小值都是不同的,左部是线段右端点横坐标对应的函数上的点,右部是线段左端点横坐标对应的函数上的点。而中间紫色部分都对应的是最低点,所以画出
那么为什么是拉长
“拉长”在代码上要用懒标记实现
至于加入一个
于是我们只需维护这个可重集,就可以维护好
具体实现上,每次加入一个点分三类讨论,若当前
在其左时,
用堆就可以维护,时间复杂度瓶颈在于堆的使用,
左边用大根堆,由于整体是下凸壳,放在左部的是单调递减的,横坐标最大的对应的就是最小值的位置。同理,右部单调递增,用小根堆。
此外还有一种方法是切比雪夫距离转曼哈顿距离
这也是一个常用的
曼哈顿距离也有个性质,一个点到一条确定的路径(类似函数的那种,每个
代码实现
#include<bits/stdc++.h>
using namespace std;
const int N=8e5+10;
int n;
typedef pair<int,int> pii;
pii a[N];
typedef long long ll;
ll ans;
priority_queue<int> L;
priority_queue<int,vector<int>,greater<int> > R;
#define sum first
#define x second
int main()
{
scanf("%d",&n);
for(int i=1,x,y;i<=n;i++)
{
scanf("%d%d",&x,&y);
a[i]={x+y,x};
}
sort(a+1,a+n+1);
L.push(a[1].x);
R.push(a[1].x);
int tagr=0;
for(int i=2;i<=n;i++)
{
tagr+=a[i].sum-a[i-1].sum;//tagr表示全局的有部分平移量标记
int l=L.top(),r=R.top()+tagr,x=a[i].x;
if(x<l)
{
L.pop(),R.push(l-tagr);
L.push(x),L.push(x);
ans+=l-x;
}// xi在最低点左边
else if(x>r)
{
R.pop(),L.push(r);
R.push(x-tagr),R.push(x-tagr);
ans+=x-r;
}// xi在最低点
else
{
L.push(x),R.push(x-tagr);
}// xi在最低点右边
}
printf("%lld\n",ans);
return 0;
}