bzoj 2716 天使玩偶 CDQ分治

题意,平面内动态加点,每次查询距离目标点曼哈顿距离最短的点,与之的距离

考虑以查询点为原点,其左下角的点与之曼哈顿距离为dis=(x-x')+(y-y')=(x+y)-(x'+y')

因此,我们考虑求(x'+y')最大值

CDQ分治来解决此题

首先考虑将所有点,无论是目标点还是插入的点,按X坐标排序

再对于时间进行分治

对于分治后得到的两段,分别在内部再次按X坐标排序,

之后创建两个指针,分别在,左半块和右半块滑动,并且始终使,右半块中指针所指的查询的点的时间,晚于左半块中插入点的时间

然后动态在树状数组中加入右半块中要插入的点

最后查询X+Y最大值

最后计算一下,直接更改点坐标,是右上等情况也满足左下的情况

共调用cdq 3次


代码如下

#include<bits/stdc++.h>
using namespace std;
const int N=1001000;
struct node{
	bool is_ques;
	int x,y,id;
}P[N],sort_by_time[N];
int e[N],ans[N],vis[N];
int n,m,cnt=0;
inline void R(int &x)
{
	x=0;
	char c=getchar();
	int p=1;
	while(c<'0'||c>'9')
	{
		if(c=='-')
			p=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9')
	{
		x=(x<<1)+(x<<3)+(c^'0');
		c=getchar();
	}
	x*=p;
}
bool comp(node a,node b){return a.x<b.x;}
int lowbit(int x)
{return x&(-x);}
void add(int pos,int val)
{
	if(!pos)return;
	while(pos<N) 
	{
		e[pos]=max(e[pos],val);
		pos+=lowbit(pos);
	}
}
int query(int pos)
{
	int res=-1;
	while(pos>0)
	{
		res=max(res,e[pos]);
		pos-=lowbit(pos);
	}
	return res;
}
void release(int pos)
{
	if(!pos)return;
	while(pos<N)e[pos]=-1,pos+=lowbit(pos);
}
void cdq(int l,int r)
{
	if(l==r)return;
	int mid=l+r>>1;
	int c1=l,c2=mid+1;
	for(int i=l;i<=r;i++)
	{
		if(P[i].id<=mid)
			sort_by_time[c1++]=P[i];
		else sort_by_time[c2++]=P[i];
	}
	for(int i=l;i<=r;i++)P[i]=sort_by_time[i];
	int j=l,temp=0;
	for(int i=mid+1;i<=r;i++)
	{
		if(P[i].is_ques)
		{
			while(P[j].x<=P[i].x&&j<=mid)
			{
				if(!P[j].is_ques)add(P[j].y,P[j].x+P[j].y);
				vis[++temp]=P[j].y;
				j++;
			}
			int maxx=query(P[i].y);
			if(maxx!=-1)
				ans[P[i].id]=min(ans[P[i].id],P[i].x+P[i].y-maxx);
		}
	}
	for(int i=1;i<=temp;i++)release(vis[i]);
	cdq(l,mid);
	cdq(mid+1,r);
}
int main()
{
//	freopen("in.in","r",stdin);
	R(n);R(m);
	int t,x,y,Max=-1;
	for(int i=1;i<=n;i++)
	{
		R(x);R(y);
		cnt++;
		P[cnt].id=cnt;
		P[cnt].x=x;
		P[cnt].y=y;
		Max=max(Max,x);
		Max=max(Max,y);
		P[cnt].is_ques=0;
	}
	for(int i=1;i<=m;i++)
	{
		R(t);R(x);R(y);
		Max=max(Max,x);
		Max=max(Max,y);
		cnt++;
		P[cnt].id=cnt;
		P[cnt].x=x;
		P[cnt].y=y;
		if(t==1)P[cnt].is_ques=0;
		else P[cnt].is_ques=1;
	}
//	cout<<Max<<endl;
	sort(P+1,P+cnt+1,comp);
	memset(e,-1,sizeof(e));
	memset(ans,127,sizeof(ans));
	cdq(1,cnt);
	
	for(int i=1;i<=cnt;i++)P[i].y=Max-P[i].y+1;
	sort(P+1,P+cnt+1,comp);cdq(1,cnt);
	
	for(int i=1;i<=cnt;i++)P[i].x=Max-P[i].x+1;
	sort(P+1,P+cnt+1,comp);cdq(1,cnt);
	
	for(int i=1;i<=cnt;i++)P[i].y=Max-P[i].y+1;
	sort(P+1,P+cnt+1,comp);cdq(1,cnt);
	
	
	for(int i=n+1;i<=cnt;i++)
		if(ans[i]<1e9)printf("%d\n",ans[i]);
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值