• Gym-102569C Manhattan Distance 曼哈顿距离的转换 二分


    Gym-102569C Manhattan Distance 曼哈顿距离的转换 二分

    题意

    给定平面上的(n)个整点((x_i,y_i)),整点之间会两两产生曼哈顿距离,求第(k)小的曼哈顿距离大小。

    [2 leq n leq 1e5\ 1 leq k le frac{n(n+1)}{2}\ -10^8 leq x_i,y_i le 10^8 ]

    分析

    此题如果直接做会发现没什么想法

    因此利用曼哈顿距离的性质:

    对于点((x_i,y_i))((x_j,y_j))。曼哈顿距离(d = |x_i - x_j| + |y_i - y_j|),切比雪夫距离(d' = max(|x_i - x_j|,|y_i - y_j|))

    变换:((x_i,y_i) => (x_i +y_i,x_i - y_i),(x_j,y_j) => (x_j +y_j,x_j - y_j))

    那么求这两点的曼哈顿距离就等价为了求切比雪夫距离

    回到这题,我们把所有点变成求切比雪夫距离。

    题目变为求第(k)小的切比雪夫距离,这显然是可以二分答案的。问题又变为求所有点中,距离(d leq 给定dis) 的对数。

    显然,可以固定(i),枚举(j < i)中符合条件的对数。根据切比雪夫距离的性质,要同时满足(|x_i - x_j|和|y_i - y_j|)小于等于dis,那么我们对x排序,对y建立权值树状数组表示符合条件的点,每次查询([y-dis,y+dis])范围的个数,为了保证(x),可以对x排序,用双指针移动来保证。

    代码

    struct BIT{
    	vector<int> c;
    	int n;
    	BIT(int n):n(n),c(n + 1,0) {}
    	void add(int pos,int x){
    		for(;pos <= n;pos += pos & -pos)
    			c[pos] += x;
    	}
    	int ask(int x){
    		int res = 0;
    		for(;x >= 1;x -= x & -x){
    			res += c[x];
    		}
    		return res;
    	}
    };
    
    vector<int> h;
    ll k;
    int n;
    int ans;
    
    int get(int x){
    	return lower_bound(h.begin(),h.end(),x) - h.begin() + 1;
    }
    
    int check(int dis,vector<pii>& p){
    	BIT bit(n);
    	ll cnt = 0;
    	for(int i = 1,j = 1;i <= n;i++){
    		while(j < i && p[j].fi  < p[i].fi - dis) {
    			bit.add(get(p[j].se),-1);
    			j++;
    		}
    		int up = upper_bound(h.begin(),h.end(),p[i].se + dis) - h.begin() ;
    		int down = lower_bound(h.begin(),h.end(),p[i].se - dis) - h.begin() + 1;
    		cnt += bit.ask(up) - bit.ask(down - 1);
    		bit.add(get(p[i].se),1);
    	}
    	return cnt;
    }
    
    
    signed main(){
    	n = rd();
    	k = rd();
    	vector<pii> v(n + 1);
    	for(int i = 1;i <= n;i++){
    		int x = rd();	
    		int y = rd();
    		v[i] = make_pair(x + y,x - y);
    		h.push_back(x - y);
    	}
    	sort(h.begin(),h.end());
    	h.erase(unique(h.begin(),h.end()),h.end());
    	sort(v.begin() + 1,v.end());
    	int l = 1,r = 5e8 + 10;
    	while(l <= r) {
    		int mid = l + r >> 1;
    		if(check(mid,v) >= k) {
    			ans = mid;
    			r = mid - 1;
    		}
    		else l = mid + 1;
    	}
    	cout << ans;
    }
    
  • 相关阅读:
    尬聊攻略丨过年回家,你最怕被亲戚问什么?
    有人被盗刷900次? 支付宝发布年终“神反转”盘点
    470余万条疑似12306用户数据遭贩卖 嫌疑人被刑拘
    利用Python实现对Web服务器的目录探测
    栈空间溢出
    KB奇遇记(6):搞笑的ERP项目团队
    探寻不同版本号的SDK对iOS程序的影响
    阅读《Android 从入门到精通》(24)——切换图片
    leetcode
    Grunt的配置及使用(压缩合并js/css)
  • 原文地址:https://www.cnblogs.com/hznumqf/p/14532955.html
Copyright © 2020-2023  润新知