E. Tracking Segments
题目大意:有一个长为n的二进制字符串,初始全为0,给出m个字符串内的区间,和q次操作,每次操作将1个位置上的字符变成1,问至少要几次操作能使m个区间内的至少一个满足区间内1的数量多于0的数量
1<=m<=n<=1e5;1<=q<=1e5
思路:可以二分答案,我们先把所有操作放到一个数组b里,然后二分枚举最少操作数x,然后取出数组b中的前x个,将其按照操作的位置从小到大排序,得到数组c,然后遍历每一个区间,在c中二分查找到左右端点的位置,两个位置之间有多少个数就是有多少个1,区间内其他的元素就是0,最后判断1的数量是否大于0的数量,大于就少操作,否则增加操作次数
//#include<__msvc_all_public_headers.hpp>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
pair<int,int> a[N];
int b[N];
int c[N];
ll n, m;
bool check(int x)
{
for (int i = 1; i <= x; i++)
{//取出前x个操作的位置
c[i] = b[i];
}
sort(c + 1, c + x + 1);//从小到大排序来二分查找
for (int i = 1; i <= m; i++)
{
int it1 = lower_bound(c + 1, c + x + 1, a[i].first)-c;//查找当前区间左端点在c中的哪
if (it1 == x + 1)
continue;
int it2 = upper_bound(c + 1, c + x + 1, a[i].second) - c;//右端点的再右一个位置
it2--;
int cnt1 = it2 - it1 + 1;//区间内1的数量
int tot = a[i].second - a[i].first + 1;//区间内总元素数
if (cnt1 > tot / 2)
return 1;
}
return 0;
}
int main()
{
cin.tie(0);
cout.tie(0);
ios::sync_with_stdio(false);
int t;
cin >> t;
while (t--)
{
cin >> n>>m;
for (int i = 1; i <= m; i++)
{//记录区间
cin >> a[i].first >> a[i].second;
}
int q;
cin >> q;
for (int i = 1; i <= q; i++)
{//记录操作位置
cin >> b[i];
}
int l = 1, r = q, ans=-1;
while (l <= r)
{//二分最小操作次数
int mid = (l + r) >> 1;
if (check(mid))
{
ans = mid;
r = mid - 1;
}
else
{
l = mid + 1;
}
}
cout << ans << endl;
}
return 0;
}