原题见1003
有n条船平行于x轴,已知初始时刻的位置,向平行于x轴正向或反向走。所有船速度大小一致。现在海哥站在x轴上,要给船拍照,角度为朝向+y方向的固定90度,可以在任意时刻、任意位置拍,问何时拍下的完整的船数量最多。
思路
对于横坐标为[x, y] 纵坐标为z的船而言,海哥可以移动的区间为[y-z, x+z]且y-z ≤ x+z。对于同向运动的船,它们在任意时刻的相对位置不发生改变,则可以记录下每个位置可见的船数量 bi 。得到两个方向的 bi 以后,相当于要求以某个位置为分界线,作为两个方向 bi 的最大值的相交位置。故要求向左走的船的后缀最大值 m0i ,以及向右走的船的前缀最大值 m1i ,O(N)扫一遍得到 max[m0i+m1i]
扫描线
输入多个线段位置,输出各个位置重叠的线段个数。
输入一个线段[l,r]时,将位置s[l]++, s[r+1]–, 则统计如下:
b[0] = s[0];
for(int i = 1;i < maxN;i++)
b[i] = b[i-1] + s[i];
离散化
由于横坐标的范围在 −106 ~ 106 ,点数量在 2×105 ,因此可以将横坐标离散化。
附代码
/*--------------------------------------------
* File Name: 2016百度之星复赛 1003
* Author: Danliwoo
* Mail: Danliwoo@outlook.com
* Created Time: 2016-05-29 17:18:58
--------------------------------------------*/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cmath>
using namespace std;
#define N 100100
struct node
{
int x, y;
node(){}
node(int x, int y): x(x), y(y) {}
void pr(){
printf("pr -> %d %d\n", x, y);
}
}p[2][N];
int a[2*N], b[2][N], tn[2], an, num[2*N], s[2][N], m[2][N];
int find(int x){
int l = 0, r = an-1;
while(a[l] != x){
int mid = (l+r)/2;
if(a[mid] == x) return mid;
if(a[mid] > x) r = mid-1;
else l = mid+1;
}
return l;
}
void solve(){
memset(num, 0, sizeof(num));
//left 后缀最大值
m[0][an-1] = b[0][an-1];
for(int i = an-2;i >= 0;i--)
m[0][i] = max(m[0][i], b[0][i]);
//right 前缀最大值
m[1][0] = b[1][0];
for(int i = 1;i < an;i++)
m[1][i] = max(m[1][i-1], b[1][i]);
int ans = 0;
for(int i = 0;i < an;i++)
ans = max(ans, m[0][i]+m[1][i]);
printf("%d\n", ans);
}
int main()
{
int T, o = 0;
scanf("%d", &T);
while(T--){
int n, x, y, z, d;
scanf("%d", &n);
memset(s, 0, sizeof(s));
memset(b, 0, sizeof(b));
memset(m, 0, sizeof(m));
memset(a, 0, sizeof(a));
tn[0] = tn[1] = an = 0;
for(int i = 0;i < n;i++){
scanf("%d%d%d%d", &x, &y, &z, &d);
if(y-z > x+z) continue;
d = (d+1)/2;
p[d][tn[d]++] = node(y-z, x+z);
a[an++] = y-z;
a[an++] = x+z;
}
sort(a, a+an); //离散化
unique(a, a+an);
a[an] = a[an-1];
for(int i = 0;i < an;i++)
if(a[i] >= a[i+1]){
an = i+1;
break;
}
for(int k = 0;k < 2;k++){
for(int i = 0;i < tn[k];i++){
int l = find(p[k][i].x);
int r = find(p[k][i].y);
s[k][l]++;
s[k][r+1]--;
}
b[k][0] = s[k][0];
for(int i = 1;i <= an;i++)
b[k][i] += b[k][i-1] + s[k][i];
}
printf("Case #%d:\n", ++o);
solve();
}
return 0;
}