AtCoder Beginner Contest 127 F - Absolute Minima

原题链接:F - Absolute Minima (atcoder.jp)

题目大意:给定一个函数f(x)=f(x)+|x-a|+b初始为0,然后输入q个查询,查询有二种操作,如果输入1,再输入二个数为a和b,更新f(x)。如果输入2,就输出f(x)的最小值以及对应的x。

思路:观察函数表达式,可以发现输入1的时候,b这个值并不会产生后续的影响。所以可以直接使用sum记录b的总和。对于a来讨论,例如如果查询为1 2 3,1 4 5,1 6 4,那么f(x)=|x-2|+|x-4|+|x-6|+12,那么如何取得最小值呢?可以从绝对值的几何意义来看,|x-2|代表x到2的距离,那么|x-2|+|x-4|+|x-6|就是x到2,4,6这些点的距离之和,如果x==2,那么f(x)=18,如果x==4,那么f(x)=16,如果x==6,那么f(x)=18,可以看出来,在中位数的时候可以取得最小的f(x)。因为会不断的加入数据,那么如何动态的维护中位数呢?可以使用对顶堆,开一个从小到大排序的堆和一个从大到小排序的堆。将二个堆拼接使用就可以动态的查找中位数了,从大到小排序的堆的堆顶就是要查找的中位数。

#pragma GCC optimize(2)
#include
#define endl '\n' 
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair pii;
const int N=1e6+10;
priority_queue,greater> p;//从小到大排序的堆 
priority_queue q;//从大到小排序的堆 
int main()
{
    ios::sync_with_stdio(NULL);
	cin.tie(0),cout.tie(0);
	ll t;cin>>t;
	ll sum=0,ans1=0,ans2=0; 
	while(t--)
	{
		ll x,y,z;cin>>x;
		if(x==1)
		{
			cin>>y>>z;
			sum+=z;//b的总和 
			q.push(y);//先把数据放到从大到小排序的堆 
			ans1+=y;
			if(q.size()-1>p.size())//如果个数为偶数那么q和p的大小相同,如果个数为奇数那么q比p大一个 
			{
				ll k=q.top();//将q中的最大值插入p中 
				p.push(k);
				q.pop();
				ans1-=k;
				ans2+=k;
			}
			if(p.size()&&q.top()>p.top())//因为会不断的插入数据,那么就可能发生q的最大值大于p的最小值 
			{
				ll a=q.top(),b=p.top();
				q.pop(),p.pop();
				q.push(b),p.push(a);
				ans1=ans1+b-a;ans2=ans2-b+a;
			}
		}
		else
		{
			ll k=q.top();
			ll ans=k*q.size()-ans1+ans2-k*p.size()+sum;//可以这样理解
			//0 1 4 6 7 8,0不在讨论范围内只是方便理解,对于这样的数据来说,中位数就是6,那么为了快速的
			//求出其他数与中位数的差值,就可以用q.size()*k-ans1来表示q里面的差值和,也就是3*6-1+4+6,这就是
			// 1 4到6的差值和,对于在p里面的数据,那么就是用ans2-k*p.size(),也就是7+8-6*2. 
			cout<

你可能感兴趣的:(算法,数据结构)