题目链接:https://ac.nowcoder.com/acm/contest/331/E
这道题在纸上画一画就会发现其实是一个区间覆盖的问题,实际上问的是第几个区间会第一次出现区间相交的情况。首先来看一下数据范围,T组数据,n和m都是100000,但是题目中说了一个点只能连一次,所以边最多有50000个,但是如果暴力的话,时间复杂度依然是50000*50000*10,显然过不了,但是在比赛的时候水了一发,竟然过了....(赛后数据加强了,就把暴力的做法卡了)。
这道题的思路其实和暴力的思路差不多,但是用树状数组去做会更巧妙一点,做法就是插点问线,顾名思义就是我们对每一个区间的左端点和右端点进行标记,然后在每次询问的时候判断这个区间内的值是否为0,如果不为0就说明出现了相交的情况。标记的方法是对每一个区间的左端点+i,右端点-i(i为第i个区间),需要注意的是每个区间用来标记的数必须不同,不能是每个左端点加1,右端点减1这样,自己画画图就知道为什么了...
AC代码:
#include <bits/stdc++.h>
#define maxn 100005
using namespace std;
int pre[maxn];
int T,n,m;
int lowbit(int x){
return x & (-x);
}
void Update(int x,int y){
for(int i=x;i<=n;i+=lowbit(i)){
pre[i] += y;
}
}
int Query(int x){
int sum = 0;
for(int i=x;i>=1;i-=lowbit(i)){
sum += pre[i];
}
return sum;
}
int main()
{
scanf("%d",&T);
while(T--){
memset(pre, 0, sizeof(pre));
bool flag = false;
scanf("%d%d",&n,&m);
int pos = -1;
for(int i=1;i<=m;i++){
int l, r;
scanf("%d%d",&l, &r);
if(l > r) swap(l, r);
if(flag == false){
int xx = Query(l - 1);
int yy = Query(r);
if(yy - xx != 0){
pos = i;
flag = true;
}
else{
Update(l, i);
Update(r, -i);
}
}
}
printf("%d\n", pos);
}
return 0;
}