C. Medium Design Codeforces Round 904 (Div. 2)

Problem - C - Codeforces

题目大意:有一个长为m的数组初始全为0,有n个区间[li,ri],每选择一个区间就要令区间内所有数+1,要求选择一些区间,使得数组的最大值-最小值最大,求这个差值

1<=n<=1e5;1<=m<=1e9

思路:我们设取得最大值的位置是i,我们要让这个最大值最大,那么所有包含这个位置的区间都要选,并设这些区间去掉重合部分后组成的大区间为[L,R],那么这个区间内最小值的取值位置一定是L或R,因为假如最小值的取值位置在LR里面,那么可以把这个位置左边或右边的区间删掉同时另一边的最大值仍然等于原来的最大值,最小值又变成了新的大区间的端点。

        所以当整个数组最小值在[L,R]外边时,这时答案就等于最大值,如果在L或R,那么需要把以L为左端点的区间删掉或把以R为右端点的区间删掉,这些区间对最大值和最小值的贡献都是1,所以删掉后ma-mi不变,两种情况取最大值即可。

        考虑如何求区间最大值,因为这题m的范围不能开数组,所以我们用对组数组记录区间的端点,左端点就是{位置,1},右端点就是{位置+1,-1},然后将所有端点从小到大排序,遍历这总共最多2e5个端点,维护前缀和同时维护最大值即可。

//#include<__msvc_all_public_headers.hpp>
#include
using namespace std;
typedef long long ll;
const ll MOD = 1e9 + 7;
const int N = 1e5 + 5;
int n;
paira[N];
void init()
{
	
}
void solve()
{
	cin >> n;
	int m;
	cin >> m;
	init();
	for (int i = 1; i <= n; i++)
	{
		int x, y;
		cin >> x >> y;
		a[i] = { x,y };
	}
	vector>num1,num2;
	ll ma = 0;
	for (int i = 1; i <= n; i++)
	{
		if (a[i].first != 1)
		{//左端点不是1的
			num1.push_back({ a[i].first,1 });//左端点是+1
			num1.push_back({ a[i].second + 1,-1 });//右端点是-1
		}
		if (a[i].second != m)
		{//右端点不是m的
			num2.push_back({ a[i].first,1 });
			num2.push_back({ a[i].second + 1,-1 });
		}
	}
	sort(num1.begin(), num1.end());//从小到大排序
	sort(num2.begin(), num2.end());
	int las = 0;//当前的下标
	ll cnt = 0;//差分数组前缀和
	for (int i = 0; i < num1.size(); i++)
	{//遍历所有端点
		if (num1[i].first > las)
		{//下标移动后维护最大值
			ma = max(ma, cnt);
		}
		cnt += num1[i].second;
		las = num1[i].first;
	}
	las = 0, cnt = 0;
	for (int i = 0; i < num2.size(); i++)
	{
		if (num2[i].first > las)
		{
			ma = max(ma, cnt);
		}
		cnt += num2[i].second;
		las = num2[i].first;
	}
	cout << ma;
	cout << '\n';
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int t;
	cin >> t;
	//t = 1;
	while (t--)
	{
		solve();
	}
	return 0;
}

你可能感兴趣的:(前缀和,差分,算法,c++,数据结构,c语言)