题目链接:https://codeforces.com/contest/1418/problem/D
题目大意:
给出N堆垃圾,每次可以使得任意一堆向左或者向右移动,如果重合就合并为一堆,问最少需要移动几次使得这些垃圾合并为两堆或者一堆?
题目思路:
首先可以考虑到 ,如果垃圾堆数 > 2,那么肯定是合并为两堆,那么就可以推一下公式,合并为哪两堆
我们可以将垃圾按位置从小到大排序
之后枚举中间点,可以发现会分成a1~ai + a_i+1 ~an 这么两堆
之后推一下公式会发现[L,R]合并成一堆时的权值即为a[R]-a[L]
所以我们可以求出一个公式,要把n堆石子化成两堆即:
a[n] - a[i+1] + a[i] - a[1] 最小
进一步:a[n] - a[1] + a[i] - a[i+1] 最小
所以对于每次询问,我们只需要知道当前的最小值、最大值、最小差值即可
可以用线段树维护,当然为了方便从set写了
Code:
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define _CRT_SECURE_NO_WARNINGS
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#pragma GCC option("arch=native","tune=native","no-zero-upper")
#pragma GCC target("avx2")
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll INF= 1e18;
const int maxn =3e5+7;
const int mod= 998244353;
inline bool read(ll &num)
{char in;bool IsN=false;
in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
multiset<ll>s1;
set<ll>s2;
ll num[maxn];
unordered_map<ll,int>mp;
int main(){
read(n);read(m);
for(int i=1;i<=n;i++) read(num[i]);
sort(num+1,num+1+n);
for(int i=1;i<=n;i++){
s2.insert(num[i]);
mp[num[i]]++;
if(i>1)
s1.insert(num[i-1] - num[i]);
}
ll ans = -*(s2.begin())+*prev(s2.end()) + *(s1.begin());
printf("%lld\n",ans);
for(int i=1;i<=m;i++){
ll op,x;read(op);read(x);
if(op){
if(!mp[x]){
auto temp = s2.lower_bound(x);
if(temp != s2.end()) s1.insert(x - *temp);
if(temp != s2.begin()) s1.insert(*prev(temp) - x);
if(temp!=s2.end()&&temp!=s2.begin()) s1.erase(s1.find(*prev(temp) - *temp));
s2.insert(x);
}
mp[x]++;
}else{
mp[x]--;
if(!mp[x]){
auto tempx = s2.upper_bound(x);
if(tempx != s2.end()) s1.erase(s1.find(x - *tempx));
auto tempy = s2.lower_bound(x);
if(tempy != s2.begin()) s1.erase(s1.find(*prev(tempy) - x));
if(tempx != s2.end() && tempy != s2.begin()) s1.insert(*prev(tempy) - *tempx);
s2.erase(x);
}
}
if(s2.size()&&s1.size()) ans = -*(s2.begin())+*prev(s2.end()) + *(s1.begin());
printf("%lld\n",ans);
}
return 0;
}
/***
5 6
1 2 6 8 10
***/