zoukankan      html  css  js  c++  java
  • BZOJ 2716/CH 4701 天使玩偶

    【题意】
    Ayu在七年前曾经收到过一个天使玩偶,当时她把它当做时间囊埋在了地下。
    而七年后的今天,Ayu却忘了她把天使玩偶埋在了哪里,所以她决定仅凭一点模糊的记忆来寻找它。
    我们把Ayu生活的小镇看做一个二维平面直角坐标系,而Ayu会不定时的记起可能在某个点(x,y)埋下了天使玩偶。
    或者Ayu会询问你,假如她在(x,y),那么她离最近的天使玩偶可能埋下的地方有多远。
    因为Ayu只会沿着平行坐标轴的方向来行动,所以在这个问题里我们定义两个点之间的距离为曼哈顿距离:
    dist(A,B)=|Ax−Bx|+|Ay−By|
    dist(A,B)=|Ax−Bx|+|Ay−By|
    其中Ax,Ay表示点A的横坐标,其余类似。

    前言:

    分治是一种有趣的方法。

    分析:

    为了去掉绝对值符号,不妨把询问分成4种,分别询问左下、左上、右下、右上方向上最近的点的距离,4个答案的最小值即为答案。
    x,yx,y为询问点的坐标,xi,yix_i,y_i为前面天使玩偶的坐标。 情况如下图:
    在这里插入图片描述
    可以发现上面(x,xi),(y,yi)(x,x_i),(y,y_i)的符号是一样的。

    我们需要用CDQ分治求解。
    主要思想就是:把前面的天使玩偶更新后面的询问。用树状数组维护前缀最大值。
    需要注意的是:

    1. memsetmemsetO(n)O(n)的,我们其实只用把修改的位置重置即可。
    2. 对于左上、右上的情况,树状数组更新的是[totyi,tot)(y+1toty+1)[tot-y_i,tot)(y先+1,tot为最大y+1)
      代码:
    #pragma GCC optimze("Ofast")
    #pragma GCC optimze(2)
    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<algorithm>
    #define g getchar()
    using namespace std;
    const int N=1e6+10;
    struct rec { int x,y,z; }a[N],b[N]; //原操作序列 
    bool operator <(rec a,rec b) {
    	return a.x<b.x||(a.x==b.x&&a.y<b.y);
    }
    int t,n,m;
    int ans[N],c[N],tot;//BIT
    
    int ask(int x) {
    	int y=c[0];
    	for(	;x;x&=x-1) y=max(y,c[x]);
    	return y;
    }
    
    void up(int x,int y) {//树状数组维护前缀最大值 
    	for(	;x<tot&&c[x]<y;x+=x&-x)	
    		c[x]=y;
    }
    
    int sta[N],top;//装上传的标号 
    
    void calc(int st,int ed,int d,int dx,int dy) {
    	for(int i=st;i!=ed;i+=d) {
    		int y=(dy==1)?b[i].y:tot-b[i].y;
    		int tmp=b[i].x*dx+b[i].y*dy;
    		if(a[b[i].z].z==1) up(y,tmp),sta[++top]=b[i].z;
    		else ans[b[i].z]=min(ans[b[i].z],tmp-ask(y));
    	}
    	while(top) //重置树状数组(避免memset) 
    		for(int x=(dy==1)?a[sta[top--]].y:tot-a[sta[top--]].y;x<tot&&c[x]>c[0];x+=x&-x)
    			c[x]=c[0];
    }
    
    void cdq(int l,int r) {
    	if(l==r||r<=n)return ;
    	int mid=(l+r)>>1;
    	cdq(l,mid);
    	cdq(mid+1,r);
    	t=0;
    	for(int i=l;i<=r;i++)
    		if( (i<=mid) ^ (a[i].z==2) )
    			b[++t]=a[i],b[t].z=i;
    	sort(b+1,b+t+1);
    	calc(1,t+1,1,1,1); calc(t,0,-1,-1,-1);
    	calc(1,t+1,1,1,-1); calc(t,0,-1,-1,1);
    }
    
    void qr(int &x) {
    	char c=g;x=0;
    	while(!isdigit(c))c=g;
    	while(isdigit(c))x=x*10+c-'0',c=g;
    }
    
    void write(int x) {
    	if(x/10)write(x/10);
    	putchar(x%10+'0');
    }
    
    void pri(int x) { write(x) ; puts("") ;}
    
    int main() {
    	qr(n);qr(m);m+=n; 
    	for(int i=1;i<=n;i++)
    		qr(a[i].x),qr(a[i].y),a[i].y++,a[i].z=1;
    	for(int i=n+1;i<=m;i++)
    		qr(a[i].z),qr(a[i].x),qr(a[i].y),a[i].y++;
    	for(int i=1;i<=m;i++)tot=max(tot,a[i].y);
    	tot++;	
    	memset(c,-63,(tot+1)<<2);
    	memset(ans,63,(m+1)<<2);
    	cdq(1,m);
    	for(int i=n+1;i<=m;i++)
    		if(a[i].z==2) pri(ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    坐标系操作
    创建重复字符的字符串
    添加和读取扩展数据
    GDI+ 透明画刷
    AutoCAD将焦点设置为绘图窗口
    DataGridView复制到Excel格式
    VB.NET 如何使用AutoCAD事件
    DataGridView禁用行标题中的三角号
    day80-drf-web开发模式、api接口、postman的使用、Restful规范(重点)、drf的安装和简单使用 、cbv源码、APIView源码分析
    day81-drf-序列化组件、简单使用、字段类型、字段选项、修改数据、read_only、write_only、查询所有、新增、删除、模型类序列化、源码分析
  • 原文地址:https://www.cnblogs.com/zsyzlzy/p/12373878.html
Copyright © 2011-2022 走看看