zoukankan      html  css  js  c++  java
  • JZOJ2866. 【集训队互测 2012】Bomb

    Description

    A 国和 B 国是两个超级大国,长期处于冷战状态;

    A 国在 B 国中设有 N 个情报站,编号为 1,2,3, …… ,N ,每个情报站有一个坐标 (Xi,Yi) 。但是, A 国的工作人员发现,每个情报站里都被埋上了炸弹!

    这些炸弹非常特殊 , 只要同时拆除其中的三个炸弹 , 所有炸弹就都不会爆炸了。

    由于各个情报站联络需要代价 , 拆除炸弹需要花费的总代价为这些炸弹两两之间的曼哈顿距离和。

    现在 A 国的指挥部门找到了你 , 希望知道可能需要的最大代价和最小代价 。

    N<=100000

    Solution

    • 画图可知求的是让三个点被围的最小矩形周长最大。
    最大值:
    • 直接找到所有点的xmax,xmin,ymax,ymin
    • 由于三个点,控制四个边界,有一个点同时控制了两个边界,枚举这个点,再分别与另外两个边界找到max就好了。
    • 关于点数:另外两个边界最多才两个点,保证了在三个点以内。而若只有一个点同时确定了两个边界,而这个矩形内没有点,画画图会发现只要有任意一个点在外面答案就会更大,所以一定有三个点。
    • 然后ans=min(max(x-xmin,xmax-x)+max(y-ymin,ymax-y)
    最小值:
    • 一定有一个点同时控制两个边界,钦定这个点为左下角(旋转后也是一样的)。
    • (1)剩下一个点控制右上角。
    • (2)还有两个点分别控制右和上。
    • (1):枚举在左下角和右上角中间的点。找到对角方向x+y或-x-y最小的点(旋转一下即为左上角和右下角),计算答案。
    • (2):按x大到小,y大到小排序。以y为关键字记录最小的x+y,最小的x。
    • 按顺序枚举左下角,查找在它上面的最小的x+y,保证在它右边。
    • 用y更新在它下方的x+y,区间修改。具体来说用区间上记录的minx+y更新min(x+y)
    • 再用x更新这一行的minx,单点修改。
    • 注意:tag遍历之前一定要清空,防止用前面(横坐标更小)的x更新后面的y,这样不满足讨论的情况。
    • 因为y只能和在它右边的x组合更新,所以确定了以上的顺序。

    O(nlogn)

    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define maxn 100005
    #define maxm 7000005
    #define maxx 1e8
    #define inf 1e9
    using namespace std;
    
    struct node{int x,y;} a[maxn],t[maxn],tmp;
    int cmp(node a,node b){return a.x>b.x||a.x==b.x&&a.y>b.y;}
    int n,i,j,k,ans;
    int tot,rt,tag[maxm],tx[maxm],ts[maxm],tl[maxm],tr[maxm];
    
    void GETMAX(){
    	int xmax=-inf,ymax=-inf,xmin=inf,ymin=inf;
    	for(i=1;i<=n;i++){
    		xmax=max(xmax,a[i].x),xmin=min(xmin,a[i].x);
    		ymax=max(ymax,a[i].y),ymin=min(ymin,a[i].y);
    	}
    	ans=0;
    	for(i=1;i<=n;i++)
    		ans=max(ans,max(a[i].x-xmin,xmax-a[i].x)+max(a[i].y-ymin,ymax-a[i].y));
    	printf("%d
    ",2*ans);
    }
    
    void rotate(){
    	for(int i=1;i<=n;i++){
    		swap(a[i].x,a[i].y);
    		a[i].x=-a[i].x;
    	}
    }
    
    int newnode(){
    	tot++;
    	tag[tot]=tx[tot]=ts[tot]=inf; tl[tot]=tr[tot]=0;
    	return tot;
    }
    
    void downtag(int x){
    	ts[x]=min(ts[x],tx[x]+tag[x]);
    	if (tl[x]) tag[tl[x]]=min(tag[tl[x]],tag[x]);
    	if (tr[x]) tag[tr[x]]=min(tag[tr[x]],tag[x]);
    	tag[x]=inf;
    }
    
    int find(int x,int l,int r,int ll,int rr){
    	if (!x) return inf;
    	if (tag[x]<inf) downtag(x);
    	if (l>rr||r<ll) return inf;
    	if (ll<=l&&r<=rr) return ts[x];
    	int mid=floor(1.0*(l+r)/2);
    	int tmp=min(find(tl[x],l,mid,ll,rr),find(tr[x],mid+1,r,ll,rr));
    	if (tl[x]) ts[x]=min(ts[x],ts[tl[x]]);
    	if (tr[x]) ts[x]=min(ts[x],ts[tr[x]]);
    	return tmp;
    }
    
    void changes(int &x,int l,int r,int ll,int rr,int p){
    	if (!x) x=newnode();
    	if (tag[x]<inf) downtag(x);
    	if (l>rr||r<ll) return;
    	if (ll<=l&&r<=rr) {
    		tag[x]=p; downtag(x);
    		return;
    	}
    	int mid=floor(1.0*(l+r)/2);
    	changes(tl[x],l,mid,ll,rr,p);
    	changes(tr[x],mid+1,r,ll,rr,p);
    	ts[x]=min(ts[tl[x]],ts[tr[x]]);
    }
    
    void changex(int &x,int l,int r,int p,int q){
    	if (!x) x=newnode();
    	if (tag[x]<inf) downtag(x);
    	tx[x]=q;
    	if (l==r) return;
    	int mid=floor(1.0*(l+r)/2);
    	if (p<=mid) changex(tl[x],l,mid,p,q);
    	else changex(tr[x],mid+1,r,p,q);	
    }
    
    int get(int x,int l,int r,int ll,int rr){
    	if (!x) return inf;
    	if (l>rr||r<ll) return inf;
    	if (ll<=l&&r<=rr) return tx[x];
    	int mid=floor(1.0*(l+r)/2);
    	return min(get(tl[x],l,mid,ll,rr),get(tr[x],mid+1,r,ll,rr));
    }
    
    void DOIT(){
    	sort(a+1,a+1+n,cmp);
    	tot=0; rt=newnode();
    	for(i=1;i<=n;i++) {
    		ans=min(ans,find(rt,-maxx,maxx,a[i].y,maxx)-a[i].x-a[i].y);
    		changes(rt,-maxx,maxx,-maxx,a[i].y,a[i].y);
    		changex(rt,-maxx,maxx,a[i].y,a[i].x);
    	}
    }
    
    int mi1[maxn],mi2[maxn];
    void DUIJIAO(){
    	sort(a+1,a+1+n,cmp);
    	tot=0; rt=newnode();
    	for(i=1;i<=n;i++) {
    		mi1[i]=get(rt,-maxx,maxx,a[i].y,maxx);
    		changex(rt,-maxx,maxx,a[i].y,a[i].x+a[i].y);
    	}
    	tot=0; rt=newnode();
    	for(i=n;i>=1;i--) {
    		mi2[i]=get(rt,-maxx,maxx,-maxx,a[i].y);
    		changex(rt,-maxx,maxx,a[i].y,-a[i].x-a[i].y);
    	}
    	for(i=1;i<=n;i++) 
    		ans=min(ans,mi1[i]+mi2[i]);
    }
    
    void GETMIN(){
    	ans=inf;
    	for(int cntf=0;cntf<4;cntf++){
    		DOIT();
    		rotate();
    	}
    	DUIJIAO();
    	rotate();
    	DUIJIAO();
    	printf("%d
    ",2*ans);
    }
    
    int main(){
    	scanf("%d",&n);
    	for(i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y);
    	GETMAX();
    	GETMIN();
    }
    
  • 相关阅读:
    JDBC 复习4 批量执行SQL
    JDBC 复习3 存取Oracle大数据 clob blob
    Oracle复习
    Linux命令(1)grep
    JDBC 复习2 存取mysql 大数据
    JDBC 复习1 DBUtil
    php 环境搭建问题
    Windows 批处理 bat 开启 WiFi 菜单选项 设置ID PWD
    Bat 批处理启动和停止Oracle 服务
    docker 学习1 WSL docker ,Windows docker
  • 原文地址:https://www.cnblogs.com/DeepThinking/p/11700912.html
Copyright © 2011-2022 走看看