牛客 Forsaken的三维数点
题目描述
Forsaken现在在一个三维空间中,空间中每个点都可以用
(x,y,z)(x,y,z)表示。突然,三维空间的主人出现了,如果Forsaken想要继续在三维空间中呆下去,他就必须回答三维空间主人的问题。
主人会在空间中坐标为
(x,y,z)(x,y,z)处加一点能量值,当他加了一定的次数之后,他会问Forsaken一个问题:如果坐标(0,0,0)(0,0,0)为球心,那么至少需要多大的半径才能使得球内的能量值总和大于或者等于kk,在这里,半径为00也是可以的。这对于Forsaken来说实在是太难了,因此他把这个问题交给了你。
输入描述:
第一行一个
nn表示操作的次数。
接下来每行首先一个整数
opop表示操作的种类。
如果
op = 1op=1,接下来33个整数x,y,zx,y,z表示能量值增加的坐标。
如果
op =2op=2,接下来一个整数kk表示要求的能量值总和。
输出描述:
对于每个
op=2op=2的操作,输出一个整数表示球的半径。(数据保证至少有一个22操作)
如果没有满足答案的半径,输出
-1−1。
示例1
输入
复制2 1 1 1 1 2 1
输出
复制2
备注:
1 ≤n≤2e5
1 ≤op≤2
-1e5 ≤x,y,z≤1e5
0≤k≤2e5
首先降维,因为题目问题的关键是举例,所以通过sqrt(x^2 + y ^2 + z ^2)降为一维。
解法一:离散化+线段树+二分查找
题目坐标最大是1e5,平方后是1e10,直接建树无法实现。但是观察数据发现,最多有1e5个输入,也就是说每次做多有1e5个点,因此想到离散化。
离散化的前提是知道全部的输入,所以想到把问题离线处理。
这样,把所有的距离输入后,从小到大排一遍序,便离散处理完了。
如何建树?
线段树中每一个中间节点存储的是它左右孩子节点的能量值的和。
更新操作时,只更新对应的点。
对于题目问题的查询操作:
每一个节点可以分为两部分,前半部分 和 后半部分。
假设查询操作的值为k,
如果k大于结点的值,则直接返回-1.
如果k小于等于前半部分的能量值,则进入前半部分继续查找k。否则,进入后半部分查询 k - sum[i << 1] 。
AC代码:

1 #include2 #include 3 #include <string.h> 4 #include 5 #include 6 #include 7 #include
解法二:简单线段树
因为查询的是距离,且距离最多是1e5A,并且题目要求的是向上取整的整数值,所以直接按ceil(sqrt(x^2 + y ^2 + z ^2))距离建树就好了。
AC代码:

1 #include2 #include 3 #include <string.h> 4 #include 5 #include 6 #include 7 #include