题目:
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=84227#problem/G
题意:
n个区间,m个询问。给出左右区间的坐标,询问x,若在区间内则求出与两端点的最小值,对于所有区间取最大值。
思路:
将所有的区间以中点为界,分成两个区间。对于两个区间进行二分查找最大值。
AC.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 1e5+5;
struct node {
int l, r;
};
node lef[maxn], rig[maxn];
int id1[maxn], id2[maxn];
bool cmp1(node x, node y)
{
if(x.l == y.l) return x.r > y.r;
return x.l < y.l;
}
bool cmp2(node x, node y)
{
if(x.r == y.r) return x.l > y.l;
return x.r < y.r;
}
int main()
{
//freopen("in", "r", stdin);
int T, ca = 1;
scanf("%d", &T);
while(T--) {
int n, m;
scanf("%d %d", &n, &m);
for(int i = 0; i < n; ++i) {
int a, b, mid;
scanf("%d %d", &a, &b);
mid = (a+b)/2;
lef[i].l = a; lef[i].r = mid;
rig[i].l = mid; rig[i].r = b;
if((a+b)%2) rig[i].l++; //如果区间长度为偶数
}
sort(lef, lef+n, cmp1);
sort(rig, rig+n, cmp2);
int cnt1 = 0, cnt2 = 0;
int tmp = -1;
for(int i = 0; i < n; ++i) {
if(lef[i].r > tmp) {
id1[cnt1++] = i;
tmp = lef[i].r;
}
}
tmp = 1000000005;
for(int i = n-1; i >= 0; --i) {
if(rig[i].l < tmp) {
id2[cnt2++] = i;
tmp = rig[i].l;
}
}
printf("Case %d:\n", ca++);
while(m--) {
int x;
scanf("%d", &x);
if(x >= rig[id2[0]].r || x <= lef[id1[0]].l) {
printf("0\n");
continue;
}
int ans = 0;
int l = 0, r = cnt1-1, mid, it;
while(l <= r) {
mid = (l+r) / 2;
it = id1[mid];
if(lef[it].r >= x) {
ans = max(ans, x - lef[it].l);
r = mid-1;
}
else l = mid+1;
}
l = 0; r = cnt2-1;
while(l <= r) {
mid = (l+r)/2;
it = id2[mid];
if(rig[it].l <= x) {
ans = max(ans, rig[it].r - x);
r = mid-1;
}
else l = mid + 1;
}
printf("%d\n", ans);
}
}
return 0;
}