[CF1418D] Trash Problem

Description

数轴上有 (n) 个点,每次操作你可以将所有位于 (x) 的点移动到 (x+1) 或者 (x-1)。求将所有点移动到不超过两个整点的最小操作次数。现在对点集做出 (q) 次修改,每次添加一个点,或者删除一个点,你需要动态维护答案。

Solution

假设任意时刻的点的坐标升序排序后的序列为 ({a_i})

考虑到答案一定等于 (max a_i - min a_i - max |a_i - a_{i-1}|),我们只需要动态维护最大的相邻点距离就可以了。

可以维护一个对于所有 (|a_i - a_{i-1}|)multiset,每次暴力插入删除即可

#include <bits/stdc++.h>
using namespace std;

#define int long long 
const int N = 1000005;

int n,m;

multiset <int> setPos;
multiset <int> setDelta;

void insert(int x)
{
    if(setPos.size()==0)
    {
        setPos.insert(x);
    }
    else
    {
        int nSetPosMin=*setPos.begin();
        int nSetPosMax=*setPos.rbegin();
        if(x<=nSetPosMin)
        {
            setDelta.insert(nSetPosMin-x);
        }
        else if(x>=nSetPosMax)
        {
            setDelta.insert(x-nSetPosMax);
        }
        else 
        {
            int nPreVal=*(--setPos.lower_bound(x));
            int nSucVal=*(setPos.lower_bound(x));
            setDelta.erase(setDelta.find(nSucVal-nPreVal));
            setDelta.insert(x-nPreVal);
            setDelta.insert(nSucVal-x);
        }
        setPos.insert(x);
    }  
}

void erase(int x)
{
    if(setPos.size()==1)
    {
        setPos.clear();
    }
    else
    {
        auto it=setPos.find(x);
        auto itPre=it,itSuc=it;
        if(it==setPos.begin())
        {
            ++itSuc;
            int nSucVal=*itSuc;
            setDelta.erase(setDelta.find(nSucVal-x));
        }
        else 
        {
            --itPre;
            ++itSuc;
            if(itSuc==setPos.end())
            {
                int nPreVal=*itPre;
                setDelta.erase(setDelta.find(x-nPreVal));
            }
            else
            {
                int nPreVal=*itPre;
                int nSucVal=*itSuc;
                setDelta.insert((nSucVal-nPreVal));
                setDelta.erase(setDelta.find(x-nPreVal));
                setDelta.erase(setDelta.find(nSucVal-x));
            }
        }
        setPos.erase(setPos.find(x));
    }
}

void printans()
{
    if(setDelta.size()==0) cout<<0<<endl;
    else cout<<*setPos.rbegin()-*setPos.begin()-*setDelta.rbegin()<<endl;
}

signed main()
{
    ios::sync_with_stdio(false);

    cin>>n>>m;

    for(int i=1;i<=n;i++)
    {
        int x;
        cin>>x;
        insert(x);
    }
    printans();

    for(int i=1;i<=m;i++)
    {
        int op,x;
        cin>>op>>x;
        if(op==0)
        {
            erase(x);
        }
        else
        {
            insert(x);
        }
        printans();
    }
    return 0;
}
原文地址:https://www.cnblogs.com/mollnn/p/13890982.html