NC53370 Forsaken的三维数点

题目链接

题目

题目描述

​ Forsaken现在在一个三维空间中,空间中每个点都可以用 \((x,y,z)\) 表示。突然,三维空间的主人出现了,如果Forsaken想要继续在三维空间中呆下去,他就必须回答三维空间主人的问题。

​ 主人会在空间中坐标为 \((x,y,z)\) 处加一点能量值,当他加了一定的次数之后,他会问Forsaken一个问题:如果坐标 \((0,0,0)\) 为球心,那么至少需要多大的半径才能使得球内的能量值总和大于或者等于 \(k\) ,在这里,半径为 \(0\) 也是可以的。这对于Forsaken来说实在是太难了,因此他把这个问题交给了你。

输入描述

第一行一个 \(n\) 表示操作的次数。
接下来每行首先一个整数 \(op\) 表示操作的种类。
如果 \(op = 1\) ,接下来 \(3\) 个整数 \(x,y,z\) 表示能量值增加的坐标。
如果 \(op =2\) ,接下来一个整数 \(k\) 表示要求的能量值总和。

输出描述

对于每个 \(op=2\) 的操作,输出一个整数表示球的半径。(数据保证至少有一个 \(2\) 操作)
如果没有满足答案的半径,输出 \(-1\)

示例1

输入

2
1 1 1 1
2 1

输出

2

备注

\(1 \leq n \leq 2e5\)
\(1 \leq op \leq 2\)
\(-1e5 \leq x, y, z \leq 1e5\)
\(0\leq k \leq 2e5\)

题解

知识点:线段树,二分,计算几何。

很简单的一道线段树上二分,考虑以半径为轴建立线段树即可。

另外,需要注意点的半径位置虽然不一定是整数,但取上整后和原问题是等价的。

时间复杂度 \(O(n\log n)\)

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

struct T {
    int sum;
    static T e() { return { 0 }; }
    friend T operator+(const T &a, const T &b) { return { a.sum + b.sum }; }
};

struct F {
    int add;
    T operator()(const T &x) { return { x.sum + add }; }
};

class SegmentTree {
    int n;
    vector<T> node;

    void update(int rt, int l, int r, int x, F f) {
        if (r < x || x < l) return;
        if (l == r) return node[rt] = f(node[rt]), void();
        int mid = l + r >> 1;
        update(rt << 1, l, mid, x, f);
        update(rt << 1 | 1, mid + 1, r, x, f);
        node[rt] = node[rt << 1] + node[rt << 1 | 1];
    }

    int find(int rt, int l, int r, int val) {
        if (l == r) return l;
        int mid = l + r >> 1;
        if (node[rt << 1].sum >= val) return find(rt << 1, l, mid, val);
        else return find(rt << 1 | 1, mid + 1, r, val - node[rt << 1].sum);
    }

public:
    SegmentTree(int _n = 0) { init(_n); }

    void init(int _n) {
        n = _n;
        node.assign(n << 2, T::e());
    }

    void update(int x, F f) { update(1, 1, n, x, f); }

    int find(int val) {
        if (val > node[1].sum) return -1;
        if (val == 0) return 0;
        return find(1, 1, n, val);
    }
};

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int n;
    cin >> n;
    SegmentTree sgt(2e5);
    while (n--) {
        int op;
        cin >> op;
        if (op == 1) {
            int x, y, z;
            cin >> x >> y >> z;
            ll dist2 = 1LL * x * x + 1LL * y * y + 1LL * z * z;
            int r = sqrt(dist2);
            if (1LL * r * r < dist2) r++;
            sgt.update(r, { 1 });
        }
        else {
            int k;
            cin >> k;
            cout << sgt.find(k) << '\n';
        }
    }
    return 0;
}
posted @ 2023-05-03 15:24  空白菌  阅读(33)  评论(0编辑  收藏  举报