set用法:https://blog.csdn.net/yas12345678/article/details/52601454

set<pair<int, int>> s
s = {[1, 14]};

优先级最高的患者,需要用[8,9]--> t=8,b=2
s = {[1,7],[10,14]};

优先级第二高区间[4,5]        --- 1
s = {[1,3], [6,7], [10,14]}

优先级第三高的区间[4,6]      --- 2
s = {[1,3], [13,14]}

此处[6,7]也没用了,因为后面的患者如果插入到[6,7]会发生医闹。
#include<bits/stdc++.h>
using namespace std ;
int main() 
{
	freopen("op.in", "r", stdin);
	freopen("op.out", "w", stdout);
	std::ios::sync_with_stdio(false) , cin.tie(0) ;
	
	int n , k ;
	cin >> n >> k ;
	vector<int> p(n + 1 , 0) ;    
	vector<int> t(n + 1 , 0) ;    
	vector<int> a(n + 1 , 0) ;    
	vector<int> b(n + 1 , 0) ;    
	for(int i = 1 ; i <= n ; i ++)  cin >> p[i] ;
	for(int i = 1 ; i <= n ; i ++)  cin >> t[i] ;
	for(int i = 1 ; i <= n ; i ++)  cin >> a[i] ;
	for(int i = 1 ; i <= n ; i ++)  cin >> b[i] ;
	vector<int> id(n + 1 , 0) ;
	for(int i = 1 ; i <= n ; i ++)  id[i] = i ;
	sort(id.begin() + 1 , id.end() , [&](int x , int y)
	{
		return p[x] < p[y] ;  // 匿名函数,等同于cmp函数,这里按p严重度小的排序
	}) ;
	set<pair<int , int>> s ;
	s.insert({1 , k}) ;  // 初始可以手术区间
	long long res = 0 ;
	for(int i = 1 ; i <= n ; i ++)
	{
		int c = id[i] ;  // 当前优先级最高的病患编号
		if(s.empty())  break ;  // s为空说明结束
		auto it = s.lower_bound({t[c] , 0}) ; // 返回>=t[c]的最小值
		auto it2 = it ;
		if(it2 != s.begin())  it2 -- ;
		if(it2 -> first <= t[c] && t[c] <= it2 -> second)  it = it2 ; // 找到可以安排手术的最早时间
		if(it != s.end()) // 没有超出s边界
		{
			t[c] = max(t[c] , it -> first) ; // 安排手术的时间是 max(ti, 最早可做的时间)
			if(t[c] <= it -> second)  // it->second 是区间右端点,满足条件说明可以插入到此区间
			{
				if(it -> first < t[c]) // it-first 是区间左端点
				{
					// 此处的操作是:1.删除[l,r] 2.插入[l,t_i-1] [t_i, r]
					// 以[1, 10] 插入[4,5] 为例,[1,10] --> [1, 3] [6, 10]
					int l = it -> first ; 
					int r = it -> second ;
					s.erase({l , r}) ;  
					s.insert({l , t[c] - 1}) ;
					s.insert({t[c] , r}) ;
					it = s.lower_bound({t[c] , 0}) ; // 更新可以安排手术的最早区间
				}
				vector<pair<int , int>> v ; // 用来存中间不可用需要删除的区间
				while(it != s.end()) // 边界判断
				{
					int l = it -> first ;
					int r = it -> second ;
					if(r - l + 1 >= b[c]) // 区间长度大于手术时间,可以安排手术
					{
						res += a[c] ; // 收钱
						s.erase(it) ; // 删除掉这段区间
						if(r - l + 1 > b[c])  s.insert({l + b[c] , r}) ; // 插入更新后的区间
						break ;
					}
					else
					{
						// 中间不可以插入的区间,也不能给后续的患者用了,否则会医闹
						v.push_back({l , r}) ; 
						it ++ ;
					}
				}
				for(auto now : v)  s.erase(now) ; // 删除中间的无用区间
			}
		}
	}
	cout << res << '\n' ;
	
	return 0 ;
}

6 条评论

  • 1