Codeforces Round 904 (Div. 2) C. Medium Design
jly:开始的想法:首先枚举max的位置。包含它的一定是全加,剩下的一定都不加。然后求所有位置的最小值。
初始全0,枚举max之后,因为是加区间,min一定在两端(最左或最右)。所以不需要枚举max,我们枚举min就好(因为加区间和初始全0,这个题的特殊性)。min只能在两端。
令 x 为最佳答案中数组 𝑎 中最大元素的位置。 在这种情况下,我们可以选择 𝑙≤𝑥≤𝑟 的所有线段,因为如果最小元素的位置在该线段之外,我们将答案增加 +1,如果在内部,我们不会使答案变得更糟。 由此可见,最小值要么出现在位置 1,要么出现在位置 m。
写法注意的点:下标从0开始,区间的左端点都-1,右端点不变,记作区间右端点右边那个位置,这样在那个位置-1就合理了。所以枚举min,首先认为min在最左边,那么f中不存左节点为0的点,因为这样的区间其实对最后的答案没有用处,在左节点+1同时也会在max处+1相当于没用。接着模拟过一遍剩下的区间。然后认为min在最右边,重新做一遍这个过程,区别就是f中不存右节点为m的点。
#include <cstdio>
#include <vector>
#include <queue>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <stack>
using namespace std;
typedef long long ll;
typedef pair<int, int>P;
const int maxn = 1e5 + 10;
const int INF = 0x3f3f3f3f;
const ll mod = 998244353;
const double eps = 1e-11;
const double pi = 3.141592653;
void solve()
{
int n, m;
cin >> n >> m;
vector<int> l(n), r(n);
for(int i = 0; i < n; ++i)
{
cin >> l[i] >> r[i];
l[i] -= 1;
}
//首先枚举最小值在最左边
vector<P> f;
for(int i = 0; i < n; ++i)
{
if(l[i] != 0)
{
f.emplace_back(l[i], 1);
f.emplace_back(r[i], -1);
}
}
int ans = 0;
int cur = 0, lst = 0;
sort(f.begin(), f.end());
for(auto [x,y] : f)
{
//cout << "(" << x << ", " << y << ") " << cur << " ";
if(x > lst)
{
ans = max(ans, cur);
}
cur += y;
lst = x;
}
if(m > lst) ans = max(ans, cur);
//然后枚举最小值在最右边
f.clear();
for(int i = 0; i < n; ++i)
{
if(r[i] != m)
{
f.emplace_back(l[i], 1);
f.emplace_back(r[i], -1);
}
}
//cout << endl;
cur = 0, lst = 0;
sort(f.begin(), f.end());
for(auto [x,y] : f)
{
//cout << "(" << x << ", " << y << ") " << cur << " ";
if(x > lst)
{
ans = max(ans, cur);
}
cur += y;
lst = x;
}
if(m > lst) ans = max(ans, cur);
cout << ans << "\n";
}
int main()
{
int t;
cin >> t;
while(t--)
{
solve();
}
return 0;
}