题目链接
这天,小蓝在二维坐标系的点 (X, Y) 上放了一个太阳,看做点光源。
他拿来了 n 条线段,将它们平行于 x 轴放置在了坐标系中,第 i 条线段的左端点在 xi, yi,长度为 li。线段之间不会有重合或部分重合的情况(但可能出现端点相交)。小蓝想知道有多少条线段能被太阳照亮(一条线段有长度大于 0 的部分被照亮就算)。
输入的第一行包含三个正整数 n, X, Y,相邻整数之间使用一个空格分隔。
接下来 n 行,第 i 行包含三个整数 xi, yi, li,相邻整数之间使用一个空格分隔。
输出一行包含一个正整数表示答案。
3 10 2000000
5 3 5
6 2 4
0 1 10
2
第一条线段在最上面被照亮,第二条线段被第一条完全挡住,第三条线段左边的一段能被照亮。
对于 30% 的评测用例,n ≤ 1000 ;
对于所有评测用例,1 ≤ n ≤ 100000, 0 ≤ xi , X ≤ 107 , 0 < yi ≤ 105 , 0 < li ≤ 100, 106 < Y ≤ 107 。
太阳 ( X , Y ) (X, Y) (X,Y) 到线段端点 ( x i , y i ) (x_i, y_i) (xi,yi) 的光线斜率为:
k = Y − y i X − x i k = \frac{Y - y_i}{X - x_i} k=X−xiY−yi
光线直线方程为:
y − y i = k ( x − x i ) y - y_i = k(x - x_i) y−yi=k(x−xi)
求与x轴交点( y = 0 y=0 y=0):
x proj = X ⋅ y i − x i ⋅ Y y i − Y = x i ( Y − y i ) + X y i Y − y i x_{\text{proj}} = \frac{X \cdot y_i - x_i \cdot Y}{y_i - Y} = \frac{x_i(Y - y_i) + X y_i}{Y - y_i} xproj=yi−YX⋅yi−xi⋅Y=Y−yixi(Y−yi)+Xyi
AC代码
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.*;
class java {
static int X,Y;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter pt = new PrintWriter(System.out);
StringTokenizer st = new StringTokenizer(br.readLine());
int n = Integer.parseInt(st.nextToken());
X = Integer.parseInt(st.nextToken());
Y = Integer.parseInt(st.nextToken());
List<int[]> list = new ArrayList<>();
for(int i = 0;i<n;i++){
st = new StringTokenizer(br.readLine());
int x = Integer.parseInt(st.nextToken());
int y = Integer.parseInt(st.nextToken());
int l = Integer.parseInt(st.nextToken());
list.add(new int[]{x,x+l,y});
}
//降序排列
Collections.sort(list,(o1,o2)->Integer.compare(o2[2],o1[2]));
TreeMap<Double,Double> map = new TreeMap<>();
int res = 0;
for(int[] arr:list){
//投影区间
double l = y0x(arr[0],arr[2]);
double r = y0x(arr[1],arr[2]);
if(merge(map,l,r)){
res++;
}
}
pt.println(res);
pt.flush();
pt.close();
}
public static double y0x(int x, int y) {
if (x == X) return x;
long a = (long) X * y;
long b = (long) Y * x;
return (b - a) / ((Y - y) * 1.0);
}
//区间合并
public static boolean merge(TreeMap<Double,Double> map,double left,double right){
Double l = map.floorKey(left);
if(l!=null&&map.get(l)>=left){
if(l<=left&&map.get(l)>=right){
return false;
}
left = Math.min(l,left);
right = Math.max(map.get(l),right);
map.remove(l);
}
Double r = map.ceilingKey(left);
while(r!=null&&r<=right){
right = Math.max(right,map.get(r));
map.remove(r);
r = map.ceilingKey(left);
}
map.put(left,right);
return true;
}
}