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;
}