A - Archery Tournament

题目大意:按时间顺序出现靶子和射击一个位置,靶子的圆心为(x, y)半径为r,即圆与x轴相切,靶子不会重叠,靶子被击中后消失,

每次射击找出哪个靶子被射中,或者没有射中靶子。

 

思路:关键点在于,圆都与x轴相切,那么我们能发现,如果射击在(x, y) 这个点,包含它的圆只可能是它左边第一个直径>= y的圆c1,

或者是它右边第一个直径 >=y 的圆c2,因为在c1 和 c2之间的圆不可能覆盖到(x, y), 因为它们的直径小于y,在c1左边和c2右边的圆

通过画图我们也能得出不肯能包含(x, y),那么每次射击我们只需要check两个圆就好了。

找圆的过程能用线段树维护,加入一个圆就在线段树对应的x的位置的值变成2*r,然后通过二分用线段树找圆,最后判一下是否在圆内。

#include<bits/stdc++.h>
#define LL long long
#define fi first
#define se second
#define mk make_pair
#define pii pair<int, int>

using namespace std;

const int N = 2e5 + 7;
const int M = 1e5 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 +7;


int n, tot, mx[N << 2], X[N], hs[N];

struct Qus {
    int op, x, y;
} qus[N];

void update(int pos, int v, int l, int r, int rt) {
    if(l == r) {
        mx[rt] = v;
        return;
    }

    int mid = l + r >> 1;
    if(pos <= mid) update(pos, v, l, mid, rt << 1);
    else update(pos, v, mid + 1, r, rt << 1 | 1);

    mx[rt] = max(mx[rt << 1], mx[rt << 1 | 1]);
}

int getMx(int L, int R, int l, int r, int rt) {
    if(l >= L && r <= R) return mx[rt];

    int mid = l + r >> 1, ans = 0;

    if(L <= mid) ans = max(ans, getMx(L, R, l, mid, rt << 1));
    if(R > mid) ans = max(ans, getMx(L, R, mid + 1, r, rt << 1 | 1));
    return ans;
}

bool check(int x, int y, int id) {
    LL dis1 = 1ll * qus[id].y * qus[id].y;
    LL dis2 = 1ll * (x - qus[id].x) * (x - qus[id].x) + 1ll * (y - qus[id].y) * (y - qus[id].y);
    return dis1 > dis2;
}

int main() {

    scanf("%d", &n);

    for(int i = 1; i <= n; i++) {
        scanf("%d%d%d", &qus[i].op, &qus[i].x, &qus[i].y);
        hs[++tot] = qus[i].x;
    }

    sort(hs + 1, hs + 1 + tot);
    tot = unique(hs + 1, hs + 1 + tot) - hs - 1;


    for(int i = 1; i <= n; i++) {
        int op = qus[i].op, x = qus[i].x, y = qus[i].y;

        int pos = lower_bound(hs + 1, hs + 1 + tot, x) - hs;

        if(op == 1) {
            X[pos] = i;
            update(pos, 2 * y, 1, tot, 1);
        } else {
            int l = 1, r = pos, ret = -1;
            while(l <= r) {
                int mid = l + r >> 1;
                if(getMx(mid, pos, 1, tot, 1) >= y) ret = mid, l = mid + 1;
                else r = mid - 1;
            }

            if(ret != -1 && check(x, y, X[ret])) {
                printf("%d\n", X[ret]);
                update(ret, 0, 1, tot, 1);
                continue;
            }

            l = pos, r = tot, ret = -1;
            while(l <= r) {
                int mid = l + r >> 1;
                if(getMx(pos, mid, 1, tot, 1) >= y) ret = mid, r = mid - 1;
                else l = mid + 1;
            }

            if(ret != -1 && check(x, y, X[ret])) {
                printf("%d\n", X[ret]);
                update(ret, 0, 1, tot, 1);
                continue;
            }

            puts("-1");

        }
    }
    return 0;
}
View Code

相关文章: