zoukankan      html  css  js  c++  java
  • #扫描线,并查集,切比雪夫距离#洛谷 5193 [TJOI2012]炸弹

    题目

    在平面上有 (n) 个炸弹 ([1 ldots n])

    每个炸弹的爆炸范围是 (|x-x_i|+|y-yi| leq R)

    如果某个炸弹爆炸了,那么它将引燃它范围内的所有炸弹。

    求出至少引燃多少炸弹才能使得所有炸弹都爆炸。


    分析

    如果把所有可能爆炸的边连起来那么就转换成求无向图的连通块个数,这个用并查集实现,
    曼哈顿距离不好做,考虑把它转换成切比雪夫距离
    但是建边可能有(O(n^2))条,考虑优化建边,将所有点按(x)坐标排序,
    那么对于每个点只要考虑对纵坐标的前驱后继点相连那么连通块的点都能够相连
    (map)维护即可


    代码

    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    #include <map>
    #define rr register
    using namespace std;
    const int N=100011;
    struct rec{int x,y;}a[N];
    int n,R,f[N],ans; map<int,int>uk;
    map<int,int>::iterator it;
    inline signed iut(){
    	rr int ans=0; rr char c=getchar();
    	while (!isdigit(c)) c=getchar();
    	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    	return ans; 
    }
    bool cmp(rec x,rec y){return x.x<y.x||(x.x==y.x&&x.y<y.y);}
    inline signed getf(int u){return f[u]==u?u:f[u]=getf(f[u]);}
    inline void uni(int x,int y){
    	rr int fa=getf(x),fb=getf(y);
    	if (fa!=fb) f[fa]=fb,--ans;
    }
    signed main(){
    	ans=n=iut(),R=iut();
    	for (rr int i=1;i<=n;++i){
    		rr int x=iut(),y=iut();
    		a[i]=(rec){x+y,x-y},f[i]=i;
    	}
    	sort(a+1,a+1+n,cmp);
    	for (rr int i=1,j=1;i<=n;++i){
    		for (;a[j].x+R<a[i].x;++j)
    		    if (uk[a[j].y]==j) uk.erase(a[j].y);
    		it=uk.lower_bound(a[i].y);
    		if (it!=uk.end()){
    			if (a[i].y+R>=it->first) uni(it->second,i);	
    		}
    		if (it!=uk.begin()){
    			--it;
    			if (it->first+R>=a[i].y) uni(it->second,i);	
    		}
    		uk[a[i].y]=i;
    	}
    	return !printf("%d",ans);
    } 
    
  • 相关阅读:
    五月杂题选做
    BJOI 2021 游记&题解
    U149858
    CF1037简要题解
    CF Round706简要题解
    联合省选 2020
    九省联考 2018 IIIDX
    九省联考 2018 秘密袭击
    AGC006F Balckout
    概率生成函数学习笔记
  • 原文地址:https://www.cnblogs.com/Spare-No-Effort/p/14980848.html
Copyright © 2011-2022 走看看