CF1534G A New Beginning

WrongAnswer_90發表於2024-06-10

My Blogs

CF1534G A New Beginning

不太懂為啥是黑。需要先會基本的 slope trick

首先切比雪夫距離可以轉成曼哈頓距離但是沒啥必要。因為只能向右上走,所以考慮把每個關鍵點歸到它屬於的斜率為 \(-1\) 的直線上,即按照 \(x_i+y_i\) 排序分類。

容易發現一定是走到了某條灰線上之後再收取該灰線上的所有點。所以設 \(f_{i,j}\) 表示走到了第 \(i\) 條線,當前橫座標為 \(j\) 的最小代價。

然後感覺一下,固定了 \(i\) 這個東西關於 \(j\) 很像是凸的。實際上可以證明這個東西是凸的。考慮歸納,首先從上一條線到這一條線的轉移形態:

\(x\) 能從上一條線藍色的部分轉移而來,那對應到函式影像上:

可以發現是把斜率大於 \(0\) 的部分像右移動了一段長度。然後對於這條線上的所有關鍵點,其對於 \(f\) 的貢獻是一個絕對值函式(\(|j-x_i|\))。然後凸函式加凸函式還是凸的,所以歸納成立。

維護這個東西的話,就是開一個對頂堆,維護最低段左側和右側的所有拐點。加入一個絕對值函式的時候,根據其和最低的一段的關係分類討論一下即可(這時可能會出現左側堆的點跑到右側堆裡去或者相反)。

最後計算答案的時候,由題意得 \(f(0)=\sum x_i\),然後可以根據這個和左側堆內的資訊來推出最低點的縱座標(實際上就是減去左側堆的所有點的橫座標)。總複雜度 \(\mathcal O(n\log n)\)

int n,len,tg,numa[800010];
pii a[800010];
vector<int> ve[800010];
priority_queue<int> q1;
priority_queue<int,vector<int>,greater<int>> q2;
inline void mian()
{
	read(n),q1.e(0),q2.e(0);int s=0;
	for(int i=1;i<=n;++i)read(a[i].fi,a[i].se),numa[++len]=a[i].se+a[i].fi,s+=a[i].fi;
	sort(numa+1,numa+1+len),len=unique(numa+1,numa+1+len)-numa-1;
	for(int i=1;i<=n;++i)ve[lower_bound(numa+1,numa+1+len,a[i].se+a[i].fi)-numa].eb(a[i].fi);
	for(int i=1;i<=len;++i)
	{
		tg+=numa[i]-numa[i-1];
		for(auto p:ve[i])
		{
			if(q1.top()<=p&&p<=tg+q2.top())q1.e(p),q2.e(p-tg);
			else if(p<q1.top())q2.e(q1.top()-tg),q1.pop(),q1.e(p),q1.e(p);
			else q1.e(q2.top()+tg),q2.pop(),q2.e(p-tg),q2.e(p-tg);
		}
	}
	while(q1.size())s-=q1.top(),q1.pop();
	write(s);
}

相關文章