cf1418D-trash problem(set 和 multiset的使用)

题目大意

初始有n堆垃圾散落在x轴上,你需要把垃圾收集到至多两个点上。每次你可以把处于i位置的垃圾,全部扫到i-1或者i+1的位置上。问至少需要几次操作才能完成任务。
之后有人捣乱q次,每次会在一个位置上制造出一堆垃圾,或者清理掉这堆垃圾。每次捣乱后需要分别求出答案。
n,q(1 - 1e5)
垃圾位置(1-1e9)

思路

给所有垃圾的位置排序,并记录下相邻垃圾之间的距离。
每一次询问的答案 = 间隔最远的两堆垃圾的距离 - 最大间隔距。
所以只需要O(log2n)的维护 垃圾的位置信息以及最大间距。

位置信息用set维护,由于可能有多个相等长度的间距,所以用multiset

用法

multiset的用法和set类似。
需要注意的是multiset的erase(x)会删除所有值为x的元素。

删除一个x元素:multiset.erase(multiset.find(x))
即使用erase(迭代器)方法。
判断元素的值否是和结尾相等: x == *–set.end()

AC代码

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

const int maxn = 1e5 + 5;
set<int>pos;
multiset<int>gap;

void ins(int x){
    
    
	pos.insert(x);
	auto cnt = pos.find(x);
	auto l = cnt;
	auto r = cnt;
	if(l != pos.begin()){
    
    
		l--;
		gap.insert(x - *l);
	}
	if(r != --pos.end()){
    
    
		r++;
		gap.insert(*r - x);
	}

	if(cnt != pos.begin() && cnt != --pos.end())gap.erase(gap.find(*r - *l));
}

void era(int x){
    
    
	auto cnt = pos.find(x);
	auto l = cnt;
	auto r = cnt;
	if(l != pos.begin()){
    
    
		l--;
		gap.erase(gap.find(x - *l));
	}
	if(r != --pos.end()){
    
    
		r++;
		gap.erase(gap.find(*r - x));
	}

	if(cnt != pos.begin() && cnt != --pos.end())gap.insert(*r - *l);
	pos.erase(x);
}

int solve(){
    
    
	if(pos.size() < 2)return 0;
	else return *--pos.end() - *pos.begin() - *--gap.end();
}

int main(){
    
    
	int n, m;
	cin >> n >> m;
	int cnt;
	for(int i = 1; i <= n ; i++){
    
    
		cin >> cnt;
		ins(cnt);
	}
	
	cout << solve() << endl;

	int op, x;
	while(m--){
    
    
		cin >> op >> x;
		if(op)ins(x);
		else era(x);
		cout << solve() << endl;
	}
}

猜你喜欢

转载自blog.csdn.net/qq_35068676/article/details/108627631
今日推荐