牛客小白月赛18——Forsaken的三维数点

这个是一个简单题,不过因为想到比标程时间复杂度更低的方法就尝试了一下。

思路:虽然加点是三维数点,但是我们要求的是半径的大小,这样的话,就可以转变为一维的问题。

   标程的解法是,用树状数组维护,然后二分答案,这样的话,时间复杂度就是O(n*logn*logn).

   但是,可以建立权值线段树,在树上跑的时候,就可以二分出答案了。

   如果左节点的个数不够的话,那么肯定要跑到右节点,这样不断二分,最终的边界就是我们要求的答案了,复杂度为 O(nlogn)。

   之所以能想到是因为之前有过类似题 ——> 传送门.

   

//#pragma comment(linker, "/STACK:1024000000,1024000000")
//#pragma GCC optimize(2)
#include <bits/stdc++.h>

using namespace std;
typedef double dou;
typedef long long ll;
typedef pair<int, int> pii;
typedef map<int, int> mii;

#define pai acos(-1.0)
#define M 200005
#define inf 0x3f3f3f3f
#define mod 1000000007
#define IN inline
#define W(a) while(a)
#define lowbit(a) a&(-a)
#define left k<<1
#define right k<<1|1
#define lson L, mid, left
#define rson mid + 1, R, right
#define ms(a,b) memset(a,b,sizeof(a))
#define Abs(a) (a ^ (a >> 31)) - (a >> 31)
#define random(a,b) (rand()%(b+1-a)+a)
#define false_stdio ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)

int tree[M<<2];
int n = 175000, Q, len;
dou x, y, z;

void Updata(int L, int R, int k,int pos) {
    if (L == R) {
        tree[k]++;
        return;
    }
    int mid = L + R >> 1;
    if (pos <= mid)Updata(lson, pos);
    else Updata(rson, pos);
    tree[k] = tree[left] + tree[right];
}

void Query(int L, int R, int k,int aim) {
    if (L == R) {
        cout << (tree[k] >= aim ? L : -1) << endl;
        return;
    }
    int Lsum = tree[left];
    int mid = L + R >> 1;
    if (Lsum >= aim)Query(lson, aim);
    else Query(rson, aim - Lsum);
}

int main() {
    false_stdio;
    cin >> Q;
    for (int i = 1,opt; i <= Q; i++) {
        cin >> opt;
        if (opt == 1) {
            cin >> x >> y >> z;
            len = ceil(sqrt(x * x + y * y + z * z));
            Updata(0, n, 1, len);
        }
        else {
            cin >> len;
            Query(0, n, 1, len);
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/caibingxu/p/11808300.html