CF Round 881 --E. Tracking Segments

You are given an array a consisting of n zeros. You are also given a set of m not necessarily different segments. Each segment is defined by two numbers li and ri (1≤li≤ri≤n) and represents a subarray ali,ali+1,…,ar of the array a.

Let's call the segment li,ri beautiful if the number of ones on this segment is strictly greater than the number of zeros. For example, if a=[1,0,1,0,1], then the segment [1,5] is beautiful (the number of ones is 3, the number of zeros is 2), but the segment [3,4] is not is beautiful (the number of ones is 1, the number of zeros is 1).

You also have q changes. For each change you are given the number 1≤x≤n, which means that you must assign an element ax the value 1.

You have to find the first change after which at least one of m given segments becomes beautiful, or report that none of them is beautiful after processing all q changes.

Input

The first line contains a single integer t (1≤t≤10^4) — the number of test cases.

The first line of each test case contains two integers n and m (1≤m≤n≤10^5) — the size of the array a and the number of segments, respectively.

Then there are m lines consisting of two numbers li and ri (1≤li≤ri≤n) —the boundaries of the segments.

The next line contains an integer q (1≤q≤n) — the number of changes.

The following q lines each contain a single integer x (1≤x≤n) — the index of the array element that needs to be set to 1. It is guaranteed that indexes in queries are distinct.

It is guaranteed that the sum of n for all test cases does not exceed 10^5.

Output

For each test case, output one integer  — the minimum change number after which at least one of the segments will be beautiful, or −1 if none of the segments will be beautiful.

题意:给定长度为n的数组,初始全是0,以及m个子段区间,然后q次修改,每次修改会使a[x]变成1,问你最少前k次修改可以使得至少一个子段区间是美丽的或者q次都无法满足输出-1,区间美丽需要满足区间内1的个数严格大于0的个数。

解析:很明显就是单点修改,区间查询加二分答案,我们可以直接用树状数组来维护区间和,如果某个区间和>区间长度的一半,那么就说明1的个数严格>0的个数,那么就是完美的。

#include 
using namespace std;
const int N=1e5+5;
int x[N],y[N],pos[N];//记录子段的左右区间以及每个修改的位置
int tr[N];
int n,m,q;
int lowbit(int x)
{
    return x&-x;
}
int add(int x,int c)
{
    for(int i=x;i<=n;i+=lowbit(i)) tr[i]+=c;
}
int sum(int x)//求tr[1~x]的前缀和 
{
    int res=0;
    for(int i=x;i;i-=lowbit(i)) res+=tr[i];
    return res;
}
bool check(int k)
{
    for(int i=1;i<=n;i++) tr[i]=0;//记得要初始化tr数组
    for(int i=1;i<=k;i++) add(pos[i],1);//对应位置修改成1
    for(int i=1;i<=m;i++)
    {
        int len=y[i]-x[i]+1;
        if(sum(y[i])-sum(x[i]-1)>len/2) return true;//如果满足一个就返回true
    }
    return false;
}
void solve()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++) scanf("%d%d",&x[i],&y[i]);
    scanf("%d",&q);
    for(int i=1;i<=q;i++) scanf("%d",&pos[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;
    }
    printf("%d\n",ans);
}
int main()
{
    int t=1;
    scanf("%d",&t);
    while(t--) solve();
    return 0;
}

你可能感兴趣的:(算法,c++,c语言)