1028 Forsaken的三维数点 思维 树状数组 二分
链接:https://ac.nowcoder.com/acm/contest/26896/1028
来源:牛客网
题目描述
Forsaken现在在一个三维空间中,空间中每个点都可以用(x,y,z)(x,y,z)(x,y,z)表示。突然,三维空间的主人出现了,如果Forsaken想要继续在三维空间中呆下去,他就必须回答三维空间主人的问题。
主人会在空间中坐标为(x,y,z)(x,y,z)(x,y,z)处加一点能量值,当他加了一定的次数之后,他会问Forsaken一个问题:如果坐标(0,0,0)(0,0,0)(0,0,0)为球心,那么至少需要多大的半径才能使得球内的能量值总和大于或者等于kkk,在这里,半径为000也是可以的。这对于Forsaken来说实在是太难了,因此他把这个问题交给了你。
输入描述:
第一行一个nnn表示操作的次数。
接下来每行首先一个整数opopop表示操作的种类。
如果op=1op = 1op=1,接下来333个整数x,y,zx,y,zx,y,z表示能量值增加的坐标。
如果op=2op =2op=2,接下来一个整数kkk表示要求的能量值总和。
输出描述:
对于每个op=2op=2op=2的操作,输出一个整数表示球的半径。(数据保证至少有一个222操作)
如果没有满足答案的半径,输出−1-1−1。
备注:
1≤n≤2e51 \leq n \leq 2e51≤n≤2e5
1≤op≤21 \leq op \leq 21≤op≤2
−1e5≤x,y,z≤1e5-1e5 \leq x, y, z \leq 1e5−1e5≤x,y,z≤1e5
0≤k≤2e50\leq k \leq 2e50≤k≤2e5
分析
乍看之下是个三维的题。但只要求半径。
所以修改操作:求出 半径并在对应位置 + 1,
查询:二分出前缀和大于等于 k 的结果就可以了。由于是动态的单点修改,区间查询,所以用树状数组。
//-------------------------代码---------------------------- //#define int ll const int N = 2e5+10; int n,m; int tr[N]; void add(int x,int c) { for(int i = x;i<N;i+=lowbit(i)) tr[i] += c; } int sum(int x) {int res = 0;for(int i = x;i;i-=lowbit(i))res += tr[i];return res;} void solve() { // cin>>n>>m; cin>>n; while(n--) { int op;cin>>op; if(op == 1) { double x,y,z;cin>>x>>y>>z; double r = ceil(sqrt(x * x + y * y + z * z)); add(r,1); // bd // dbbb(x,y,z); } else { int k;cin>>k; int l = 0,r = 2e5; while(l < r) { int mid = l + r >> 1; if(sum(mid) >= k) r = mid ; else l = mid + 1; } if(l == 2e5) l = -1; cout<<l<<endl; } } } void main_init() {} signed main(){ AC();clapping();TLE; cout<<fixed<<setprecision(12); main_init(); // while(cin>>n,n) // while(cin>>n>>m,n,m) // int t;cin>>t;while(t -- ) solve(); // {solve(); } return 0; } /*样例区 */ //------------------------------------------------------------