codeforces-Ed95-D

codeforces-Ed95-D

九月 15, 2020

D. Trash Problem

题意

给出n<1e5个不重复的点表示n个物品在x轴上的位置1<=pos<=1e9

要求将物品整理成最多2堆,

每次可以将一堆物品(在pos1)移动到某个位置(pos2) 消耗abs(pos2-pos1)的体力

当某些物品在同一个位置时就成为一堆 将被一起移动 移动消耗的体力仍然按距离算

q(1e5)组询问

每次输入两个数ops和pos

当ops=0时表示在上一次询问状态下 删除掉pos位置上的物品

当ops=1时表示在上一次询问状态下 在pos位置上增加物品

每次询问输出能将物品全部整理好的最少消耗体力

题解

当我们将所有物品汇聚到一堆时消耗的最少体力显然=最右端物品位置-最左端物品位置

显然当物品大于2个的时候分成两堆更省力

最少消耗体力=最右端物品位置-最左端物品位置-最大相邻物品的间隔

(自己想当然的觉得以最右端和最左端的中间点为分割点 左半边归一堆,右半边归一堆)

剩下问题是如何处理多组询问

set具有优秀的查询能力 所以我们选择维护一个储存位置信息的set 和一个间距信息的multiset

每次询问时 :

  • 若加入一个新物品 x 则 需要在set中加入x的位置

    同时在multiset里删除 x下一个物品的位置-x上一个物品的位置;

    在multiset里加入x下一个物品的位置 - x的位置

    在multiset里加入x的位置 - x上一个物品的位置

  • 若删除一个物品 x 则 需要在set删除x的位置

    同时在multiset里加入 x下一个物品的位置-x上一个物品的位置;

    在multiset里删除x下一个物品的位置 - x的位置

    在multiset里删除x的位置 - x上一个物品的位置

  • 注意上述操作需要判断插入/删除是否发生在最右端或最左端

这里需要特别提醒set的一些用法误区和一些小技巧

  • set的end()返回的是set的size并不是最后一个元素

  • set的erase()参数可以是值也可以是值对应的指针

  • multiset中erase()删除某个值(key)代表删除所有等于这个值的元素,

    若只想删除其中一个则使用multset.erase(multset.find(key) )

  • set的find(key)时间复杂度为logn 返回key的指针

  • 插入单个元素会返回一个 pair<iterator,bool> 对象

  • 注意set的指针对应元素会在插入/删除操作后产生变化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define endl '\n'
#define Turnoff std::ios::sync_with_stdio(false)
const ll Max=1e5+5;
const ll Mod=998857459;
/*

*/
set<int>piles;
multiset<int>gap;
vector<int>arr;
int main() {
Turnoff;
int n,q;cin>>n>>q;
int last=0;
for(int i=1;i<=n;i++){
int temp;cin>>temp;
arr.push_back(temp);
piles.insert(temp);
}
sort(arr.begin(),arr.end());
for(int i=1;i<arr.size();i++)gap.insert(arr[i]-arr[i-1]);
if(piles.size()<=2)cout<<0<<endl;
else{
int maxpos=*(--piles.end()),minpos=*(piles.begin());
int maxgap=*(--gap.end());
cout<<maxpos-minpos-maxgap<<endl;
}
while(q--){
int op,pos;cin>>op>>pos;
if(op){
auto it=piles.insert(pos).first;
//cout<<it<<endl;
if(next(it)!=piles.end())gap.insert(*next(it)-pos);
if(it!=piles.begin())gap.insert(pos-*prev(it));
if(it!=piles.begin()&&next(it)!=piles.end())gap.erase(gap.find(*next(it)-*prev(it)));
}
else {
auto it=piles.find(pos);
if(next(it)!=piles.end())gap.erase(gap.find(*next(it)-pos));
if(it!=piles.begin())gap.erase(gap.find(pos-*prev(it)));
if(it!=piles.begin()&&next(it)!=piles.end())gap.insert(*next(it)-*prev(it));
piles.erase(pos);
}
if(piles.size()<=2)cout<<0<<endl;
else{
int maxpos=*(--piles.end()),minpos=*(piles.begin());
int maxgap=*(--gap.end());
cout<<maxpos-minpos-maxgap<<endl;
}
}
}