[Violet 3]天使玩偶

Posted by Dispwnl on April 17, 2018

题目

题目描述

Ayu 在七年前曾经收到过一个天使玩偶,当时她把它当作时间囊埋在了地下。而七年后 的今天,Ayu 却忘了她把天使玩偶埋在了哪里,所以她决定仅凭一点模糊的记忆来寻找它。

我们把 Ayu 生活的小镇看作一个二维平面坐标系,而 Ayu 会不定时地记起可能在某个点 (xmy) 埋下了天使玩偶;或者 Ayu 会询问你,假如她在 (x,y) ,那么她离近的天使玩偶可能埋下的地方有多远。

因为 Ayu 只会沿着平行坐标轴的方向来行动,所以在这个问题里我们定义两个点之间的距离为$dist(A,B)=\vert Ax-Bx\vert+\vert Ay-By\vert$。其中 Ax 表示点 A的横坐标,其余类似。

输入输出格式

输入格式:

第一行包含两个整数n和m ,在刚开始时,Ayu 已经知道有n个点可能埋着天使玩偶, 接下来 Ayu 要进行m 次操作

接下来n行,每行两个非负整数 (xi,yi),表示初始n个点的坐标。

再接下来m 行,每行三个非负整数 t,xi,yi。

如果t=1 ,则表示 Ayu 又回忆起了一个可能埋着玩偶的点 (xi,yi) 。

如果t=2 ,则表示 Ayu 询问如果她在点 (xi,yi) ,那么在已经回忆出来的点里,离她近的那个点有多远

输出格式:

对于每个t=2 的询问,在单独的一行内输出该询问的结果。

输入输出样例

输入样例#1:

2 3 
1 1 
2 3 
2 1 2 
1 3 3 
2 4 2

输出样例#1:

1 
2

说明

n,m<=300 000

xi,yi<=1 000 000

题解

可以把时间看成$1$个条件(初始点为$0$),坐标为$2$个条件

这样就成了一个三维偏序问题,似乎可以用$CDQ分治$搞了

然而曼哈顿距离带了个绝对值很烦人

所以分$4$种情况讨论

发现四种情况都可以看成是一个大矩阵套一个小矩阵

情况$1$:

这是最简单的情况,直接找到二分左边的最大值减就行了

情况$2$:

这种情况肯定不能直接减了

我们发现,用最大值减去$A,B$的$x$,可以得到两个新的矩阵$C,D$,而ta们满足条件$1$,而且答案不变

所以这么处理就行了

情况$3$、$4$同样处理

代码

# include<iostream>
# include<cstring>
# include<cstdio>
# include<cstdlib>
# include<algorithm> 
# define mid (l+r>>1)
using namespace std;
const int MAX=1e6+1;
int s[MAX];
int n,m,tot,maxn,maxx;
int ans[MAX];
int read()
{
	int x=0;
	char ch=getchar();
	for(;!isdigit(ch);ch=getchar());
	for(;isdigit(ch);x=x*10+ch-48,ch=getchar());
	return x;
}
struct q{
	int a,b,c,fl;
	void Read()
	{
		b=read()+1,c=read()+1;
		maxn=max(maxn,c),maxx=max(maxx,b);
	}
}f[MAX],c[MAX];
bool cmp(q a,q b)
{
	if(a.b!=b.b)
	return a.b<b.b;
	return a.a<b.a;
}
int lowbit(int x)
{
	return x&(-x);
}
void change(int x,int dis)
{
	for(int i=x;i<=maxn;i+=lowbit(i))
	  s[i]=max(s[i],dis);
}
int ask(int x)
{
	int ans=0;
	for(int i=x;i;i-=lowbit(i))
	  ans=max(ans,s[i]);
	return ans;
}
void cover(int x)
{
	for(int i=x;i<=maxn;i+=lowbit(i))
	  s[i]=0;
}
void solve(int l,int r)
{
	if(l==r) return;
	int L1=l-1,L2=mid;
	for(int i=l;i<=r;++i)
	  if(f[i].a<=mid) c[++L1]=f[i];
	  else c[++L2]=f[i];
	memcpy(f+l,c+l,sizeof(q)*(r-l+1));
	int L=l;
	for(int i=mid+1;i<=r;++i)
	  if(f[i].fl==2)
	  {
	  	for(;f[L].b<=f[i].b&&L<=mid;++L)
	  	  if(f[L].fl==1) change(f[L].c,f[L].c+f[L].b);
	  	int tot1=ask(f[i].c);
		if(tot1) ans[f[i].a]=min(ans[f[i].a],f[i].b+f[i].c-tot1);
	  }
	for(int i=l;i<L;++i)
	  if(f[i].fl==1) cover(f[i].c);
	solve(l,mid),solve(mid+1,r);
}
int main()
{
	n=read(),m=read();
	for(int i=1;i<=n;++i)
	  f[++tot].Read(),f[tot].fl=1,f[tot].a=tot;
	for(int i=1;i<=m;++i)
	  f[++tot].fl=read(),f[tot].Read(),f[tot].a=tot;
	++maxn,++maxx;
	memset(ans,1,sizeof(ans));
	sort(f+1,f+1+tot,cmp);
	solve(1,tot);
	for(int i=1;i<=tot;++i)
	  f[i].b=maxx-f[i].b;
	sort(f+1,f+1+tot,cmp);
	solve(1,tot);
	for(int i=1;i<=tot;++i)
	  f[i].c=maxn-f[i].c;
	sort(f+1,f+1+tot,cmp);
	solve(1,tot);
	for(int i=1;i<=tot;++i)
	  f[i].b=maxx-f[i].b;
	sort(f+1,f+1+tot,cmp);
	solve(1,tot);
	for(int i=1;i<=tot;++i)
	  if(ans[i]<1e7) printf("%d\n",ans[i]);
	return 0;
}