1. 程式人生 > 其它 >Luogu P3644 八鄰旁的橋

Luogu P3644 八鄰旁的橋

Luogu 3644 八鄰旁的橋

solution

\(\quad\)首先考慮 \(k=1\) 的情況,其實抽象一下很像之前做的中位數的題,答案就是所有位置的中位數。

\(\quad\)再考慮 \(k=2\) 的情況,那麼無非就是將一條河分成兩邊,一邊走這個\(\quad\)橋,另一邊走那個橋。於是我們列舉分割點,這樣就轉換成了第一種情況。

\(\quad\)但是如何求第一種情況的路程和?

\(\quad\)我們可以想象一個數軸上,橋在一個點,那麼總距離就是橋到左邊點的總距離加上橋到右邊點的總距離,一旦決定了分割點,那麼橋就是那一塊所有座標的中位數。

\(\quad\)因為居民的位置滿足單調性,於是我們可以從左到右掃一遍預處理左邊塊的答案,再從右到左掃一遍預處理右邊塊的答案。

\(\quad\)每加入一個居民,就是加入了 \(2\) 個點,我們需要維護當前所有數的中位數和小於中位數的和,和大於中位數的和。都說了每次只加入 \(2\) 個點,也就是我們只用考慮這 \(2\) 個點影響,那就好維護多了,這裡維護的操作很明顯可以用平衡樹做,但是也可以用對頂堆做,操作的時候可以記錄比中位數小的數的個數和總和,比中位數大的數的個數和總和,或者也可以直接記錄答案。

code

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1000010;
struct node
{
	int a,b;
}p[maxn];
bool cmp(node a,node b)
{
	return a.a+a.b<b.a+b.b;
}
int k,n,ans;
int x1,x2;
char c1,c2;
int tot,cnt;
int s1,s2;
int sum[2][10000010],p1[1000010];
priority_queue<int ,vector<int> ,less<int> > q1;
priority_queue<int ,vector<int> ,greater<int> > q2;
signed main()
{
	cin>>k>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>c1>>x1>>c2>>x2;
		if(c1==c2) ans+=abs(x2-x1);
		else
		{
			ans++;
			p[++tot].a=x1;
			p[tot].b=x2;
			p1[++cnt]=x1;
			p1[++cnt]=x2;
		}
	}
	if(k==1)
	{
		sort(p1+1,p1+1+cnt);
		int pos=p1[cnt/2];
		for(int i=1;i<=cnt;i++)
		{
			ans+=abs(p1[i]-pos);
		}
		cout<<ans<<endl;
	}
	else
	{
		sort(p+1,p+1+tot,cmp);
		for(int i=1;i<=tot;i++)
		{
			q1.push(p[i].a);
			q1.push(p[i].b);
			s1+=p[i].a+p[i].b;
			s2+=q1.top();
			s1-=q1.top();
			q2.push(q1.top());
			q1.pop();
			if(q1.top()>q2.top())
			{
				int num1=q2.top();
				int num2=q1.top();
				q1.pop(); 
				q2.pop();
				q2.push(num2); 
				q1.push(num1);
				s1+=num1-num2; 
				s2-=num1-num2; 
			}
			sum[0][i]=s2-s1;
		}
		while(q1.size()) q1.pop();
		while(q2.size()) q2.pop();
		s1=s2=0;
		for(int i=tot;i>=1;i--)
		{
			q1.push(p[i].a);
			q1.push(p[i].b);
			s1+=p[i].a+p[i].b;
			s2+=q1.top();
			s1-=q1.top();
			q2.push(q1.top());
			q1.pop();
			if(q1.top()>q2.top())
			{
				int num1=q2.top();
				int num2=q1.top();
				q1.pop(); 
				q2.pop();
				q2.push(num2); 
				q1.push(num1);
				s1+=num1-num2; 
				s2-=num1-num2; 
			}
			sum[1][i]=s2-s1;
		}
		long long anss=1e18;
		for(int i=1;i<=tot+1;i++)
		{
			anss=min(anss,sum[0][i-1]+sum[1][i]);
		}
		cout<<ans+anss;
	}
	return 0;
}