时空限制 2000ms-3000ms / 128MB
题目描述
Ayu 在七年前曾经收到过一个天使玩偶,当时她把它当作时间囊埋在了地下。而七年后 的今天,Ayu 却忘了她把天使玩偶埋在了哪里,所以她决定仅凭一点模糊的记忆来寻找它。
我们把 Ayu 生活的小镇看作一个二维平面坐标系,而 Ayu 会不定时地记起可能在某个点 (xmy) 埋下了天使玩偶;或者 Ayu 会询问你,假如她在 (x,y) ,那么她离近的天使玩偶可能埋下的地方有多远。
因为 Ayu 只会沿着平行坐标轴的方向来行动,所以在这个问题里我们定义两个点之间的距离为dist(A,B)=|Ax-Bx|+|Ay-By|。其中 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 的询问,在单独的一行内输出该询问的结果。
说明
n,m<=300 000
xi,yi<=1 000 000
题目分析
对于一个询问点
(xi,yi)
(
x
i
,
y
i
)
假如我们只考虑其左下角与其最近的点
那么有
|xi−xj|+|yi−yj|=(xi+yi)−(xj+yj)
|
x
i
−
x
j
|
+
|
y
i
−
y
j
|
=
(
x
i
+
y
i
)
−
(
x
j
+
y
j
)
也就是说我们只需要找到一个
j
j
使得且
xj+yj
x
j
+
y
j
最大
就找到了
(xi,yi)
(
x
i
,
y
i
)
左下角离他最近的点
当然查找到的点必须在该询问点之前已被给出
所以我们给每个点加上时间戳,对于上述还要满足
tj<ti
t
j
<
t
i
到这里三维偏序已经很明显了,可以用CDQ分治
注意只查询一次左下角肯定不对
但我们可以通过旋转坐标把四个方位都转化为左下角查询
即四次 CDQ分治
这题在luogu时间卡的hin紧
尽管各种乱搞优化,最后还是吸了氧才过
至于有什么乱搞优化
1.每次CDQ前按时间戳排序很浪费时间,读入用临时数组,CDQ前再复制一遍
2.每次CDQ前把肯定不会在某个询问左下角的点删掉
#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long lt;
#define lowbit(x) ((x)&(-x))
int read()
{
int f=1,x=0;
char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
return x*f;
}
const int maxn=600010;
int n,m,cnt;
struct node{int t,x,y,f;}a[maxn],b[maxn],c[maxn];
int mx[maxn*5],mxy=-1e9;
int ans[maxn],rem[maxn];
int cmin(int x,int y){return x<y?x:y;}
int cmax(int x,int y){return x>y?x:y;}
void add(int x,int v){ for(int i=x;i<=mxy;i+=lowbit(i))mx[i]=cmax(mx[i],v);}
int query(int x){ int res=0; for(int i=x;i>0;i-=lowbit(i))res=cmax(res,mx[i]); return res;}
void cls(int x){ for(int i=x;i<=mxy;i+=lowbit(i))mx[i]=0;}
void CDQ(int ll,int rr)
{
if(ll==rr) return;
int mid=ll+rr>>1;
CDQ(ll,mid); CDQ(mid+1,rr);
int t1=ll,t2=mid+1,p=ll;
while(t2<=rr)
{
while(a[t1].x<=a[t2].x&&t1<=mid)
{
if(a[t1].f==1)add(a[t1].y,a[t1].x + a[t1].y);
b[p++]=a[t1++];
}
if(a[t2].f==2)
{
int tt=query(a[t2].y);
if(tt)ans[a[t2].t]=cmin( ans[a[t2].t], a[t2].x+a[t2].y-tt);
}
b[p++]=a[t2++];
}
for(int i=ll;i<t1;++i)
if(a[i].f==1)cls(a[i].y);
while(t1<=mid) b[p++]=a[t1++];
while(t2<=rr) b[p++]=a[t2++];
for(int i=ll;i<=rr;++i) a[i]=b[i];
}
void init(int d)
{
int mxx=0,myy=0; cnt=0;
for(int i=1;i<=n+m;++i)
{
if(d==1) c[i].x=mxy-c[i].x;
else if(d==2) c[i].y=mxy-c[i].y;
if(c[i].f==2)mxx=cmax(mxx,c[i].x),myy=cmax(myy,c[i].y);
}
for(int i=1;i<=n+m;++i)
if(c[i].x<=mxx&&c[i].y<=myy)
a[++cnt]=c[i];
}
int main()
{
n=read();m=read();
for(int i=1;i<=n;++i)
{
c[i].x=read()+1; c[i].y=read()+1,
c[i].t=i; c[i].f=1;
mxy=cmax(mxy,cmax(c[i].x,c[i].y));
}
for(int i=n+1;i<=m+n;++i)
{
c[i].f=read(); c[i].x=read()+1; c[i].y=read()+1; c[i].t=i;
if(c[i].f==2) rem[++rem[0]]=c[i].t,ans[c[i].t]=1e9;
mxy=cmax(mxy,cmax(c[i].x,c[i].y));
}
mxy++;
init(0); CDQ(1,cnt);
init(1); CDQ(1,cnt);
init(2); CDQ(1,cnt);
init(1); CDQ(1,cnt);
for(int i=1;i<=rem[0];++i)
printf("%d\n",ans[rem[i]]);
return 0;
}