线段树裸题 牛客小白月赛18 G题 Forsaken的三维数点

本文介绍了一道结合线段树与几何思维的算法题,目标是在三维空间中通过线段树实现能量值的单点更新与区间求和,以找到满足特定条件的最小球半径。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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。


一道线段树+思维的题目;
线段树单点更新,维护区间的和;当要查找时,只需找出距离最左端的点;

注意longlong

代码:

#include<bits/stdc++.h>
#define LL long long
#define pa pair<int,int>
#define lson k<<1
#define rson k<<1|1
//ios::sync_with_stdio(false);
using namespace std;
const int N=200100;
const int M=200100;
const LL mod=1e9+7;
int len(LL a,LL b,LL c){
	return (int)ceil(sqrt((a*a)+(b*b)+(c*c)));
}
int z,mmin;
struct Node{
	int l,r,w;
}tr[N<<2];
inline void build(int k,int ll,int rr){
	tr[k].l=ll,tr[k].r=rr,tr[k].w=0;
	if(ll==rr) return;
	int mid=(ll+rr)>>1;
	build(lson,ll,mid);
	build(rson,mid+1,rr);
}
inline void add(int k){
	if(tr[k].l==tr[k].r){
		tr[k].w++;
		return;
	}
	int mid=(tr[k].l+tr[k].r)>>1;
	if(z<=mid) add(lson);
	else add(rson);
	tr[k].w=tr[lson].w+tr[rson].w;
}
inline int ask(int k,int s){
	if(tr[k].l==tr[k].r) return tr[k].l;
	if(s<=tr[lson].w) return ask(lson,s);
	else return ask(rson,s-tr[lson].w);
}
int main(){
	ios::sync_with_stdio(false);
	int n;
	cin>>n;
	LL a,b,c;
	build(1,0,N);
	for(int i=1;i<=n;i++){
		int op;
		cin>>op;
		if(op==1){
			cin>>a>>b>>c;
			z=len(a,b,c);
			add(1);
		}
		else{
			cin>>z;
			if(z>tr[1].w){
				cout<<-1<<endl;
				continue;
			}
			cout<<ask(1,z)<<endl;
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值