Problem Specification Value
Time Limit 1 Sec
Memory Limit 162 MB
Submit 5628
Solved 2137

Description

在 xoy 直角坐标平面上有 n 条直线 L1, L2,. ...... Ln, 若在 y 值为正无穷大处往下看, 能见到 Li 的某个子线段, 则称 Li 为可见的, 否则 Li 为被覆盖的.

例如, 对于直线:

L1: y=x; L2: y=-x; L3: y=0

则 L1 和 L2 是可见的, L3 是被覆盖的.

给出 n 条直线, 表示成 y=Ax+B 的形式 (|A|,|B|<=500000), 且 n 条直线两两不重合. 求出所有可见的直线.

Input

第一行为 N (0 < N < 50000), 接下来的 N 行输入 Ai, Bi

Output

从小到大输出可见直线的编号, 两两中间用空格隔开, 最后一个数字后面也必须有个空格

Sample Input

3
-1 0
1 0
0 0

Sample Output

1 2

HINT

Source


Explanation

由于方程可以用 y = kx + b 表示, 说明这条直线一定不平行于 y 轴. 进一步, 我们将这些直线按照斜率排序, 由此可以得出按照斜率从小到大排好序的一坨直线. 有这样一些可以臆想出来的引理:

  1. 左右两端的直线都是可见的直线.
  2. 经斜率排序后, 若一个夹在中间的直线与两边的直线的交点负相应地 (就是说, 方向相反, 左边的直线交点在右边, 以此类推) 分居于这两条直线的交点的两侧, 则这条直线一定是不可见的.
  3. 对于相同斜率的直线, 他们中 y 截距最小的对引理 2 中的中间直线影响最大.
  4. 对于相同斜率的直线, y 截距不是最大的直线一定不能被看见.

我们用这种方法就可以计算出相应的 2n 个交点, 同时可以计算凸包.

题外话: 我突然突发奇想写了一个在本地用来跑对拍的 Python 代码. 有兴趣的人可以拿去试一试 (自带编译, 参数自调)


import os
import sys
import re
from pydatagen import *

gen = sys.argv[1]
mycode = sys.argv[2]
std = sys.argv[3]
count = int(sys.argv[4])
gpp_invoke = '"C:\\Program Files (x86)\\Dev-Cpp\\MinGW64\\bin\\g++" %s -o %s'

# Pre-run compilation

printf('$ Compiling...\r')
mycode_e = re.sub('\\.cpp$', '.exe', mycode)
std_e = re.sub('\\.cpp$', '.exe', std)
if not os.path.exists(mycode_e):
    os.system(gpp_invoke % (mycode, mycode_e))
if not os.path.exists(std_e):
    os.system(gpp_invoke % (std, std_e))
printf('$ Compiling... OK\n')

# Execution and judging

same_count = 0

for i in range(0, count):
    printf('$ Checking round #%s: Generating data...%s\r' % (str(i + 1), ' ' * 16))
    os.system('python %s > __input__.txt' % gen)
    printf('$ Checking round #%s: Running "%s"...%s\r' % (str(i + 1), mycode, ' ' * 16))
    os.system('cat __input__.txt | %s > __out1__.txt' % mycode_e)
    printf('$ Checking round #%s: Running "%s"...%s\r' % (str(i + 1), std, ' ' * 16))
    os.system('cat __input__.txt | %s > __out2__.txt' % std_e)
    printf('$ Checking round #%s: Judging...%s\r' % (str(i + 1), ' ' * 16))
    f1 = open('__out1__.txt', 'r', encoding='utf-8')
    f2 = open('__out2__.txt', 'r', encoding='utf-8')
    str1 = f1.read().replace(r'[ \t\r\n]', '')
    str2 = f2.read().replace(r'[ \t\r\n]', '')
    f1.close()
    f2.close()
    same = str1 == str2
    if same:
        printf('$ Checking round #%s: OK%s\r' % (str(i + 1), ' ' * 16))
        same_count += 1
    else:
        printf('$ Checking round #%s: CORRECT%s\r' % (str(i + 1), ' ' * 16))
    printf('\n')

printf('$ Cleaning up...\r')
os.system('rm -f __input__.txt __out1__.txt __out2__.txt')
printf('$ Finished %d rounds, of which %d are correct\n' % (count, same_count))


#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <stack>
#include <map>

using namespace std;
const int maxn = 50100;

int             n, A[maxn], B[maxn];
int             seen[maxn];
map<int, int>   msort;
stack<int>      lres; // The result of lines
stack<double>   nodex; // X-axis values of vertexes

int main(int argc, char** argv)
{
    scanf("%d", &n);
    // Input data and meke sorts according to their k values.
    for (int i = 1; i <= n; i++) {
        seen[i] = 1;
        scanf("%d%d", &A[i], &B[i]);
        if (!msort[A[i]]) msort[A[i]] = i;
        else if (B[msort[A[i]]] < B[i]) msort[A[i]] = i;
    }
    // Preparing to calculate convex hull
    map<int, int>::iterator itert = msort.begin();
    lres.push(itert++->second);
    for (itert; itert != msort.end(); itert++) {
        int     l1 = itert->second; // The first line to deal with: the line to be added
        double  newx = 0.0;
        while (true) {
            int l2 = lres.top(); // The line to be checked
            newx = (double)(B[l2] - B[l1]) / (double)(A[l1] - A[l2]); // Calculate current X intersect
            if (nodex.empty()) break; // Now it should stop as it's reaching the #1 line.
            double lastx = nodex.top(); // Get last X-axis value intersection
            if (newx > lastx) break; // The new line shall live peacefully with the others
            // Then it might be removed, to make place for the new one...
            lres.pop();
            nodex.pop();
        }
        // Anyway it should be inserted.
        lres.push(l1);
        nodex.push(newx);
    }
    // We've got all, outputting
    msort.clear(); // This is a trick to avoid memory wasting
    while (!lres.empty()) {
        msort[lres.top()] = 1;
        lres.pop();
    }
    for (itert = msort.begin(); itert != msort.end(); itert++)
        printf("%d ", itert->first);
    return 0;
}

from pydatagen import *
n = randrange(1, 50000)
printf('%d\n' % n)
for i in range(0, n):
    a = randrange(-500000, 500000)
    b = randrange(-500000, 500000)
    printf('%d %d\n' % (a, b))
fclose()