题目链接
题意:平面上原有一些点,支持动态加点,动态查询与某个点曼哈顿距离最小的点的距离。
这题据说是有 KD-Tree 和 CDQ 分治两种做法,又据说 KDT 会被卡,于是我采用 CDQ (其实是不会 KDT)
考虑给每个加点/查询操作给一个 t t t 值,作为它的第三个坐标。每次查询先只考虑 x < x i , y < y j , t < t i x
∣ x 1 − x 2 ∣ + ∣ y 1 − y 2 ∣ = ( x 1 + y 1 ) − ( x 2 + y 2 ) ( x 1 ≥ x 2 , y 1 ≥ y 2 ) |x_1-x_2|+|y_1-y_2|=(x_1+y_1)-(x_2+y_2)\ (x_1\geq x_2,y_1\geq y_2) ∣x1−x2∣+∣y1−y2∣=(x1+y1)−(x2+y2) (x1≥x2,y1≥y2),即对于点 ( x 1 , y 1 , t 1 ) (x_1,y_1,t_1) (x1,y1,t1),要找到小于这个点的 x 2 + y 2 x_2+y_2 x2+y2 的最大值。
所有点已经按 t t t 排好序了。CDQ 合并前后两段区间时按照 x x x 归并,同时建树状数组以维护 y < i yy<i 的点中, x + y x+y x+y 的最大值。
注意常数:
#include
#include
#include
#include
using namespace std;
inline int getint(){
int ans=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
ans=ans*10+c-'0';
c=getchar();
}
return ans*f;
}
inline void Min(int &x,const int &y){
x=(x<y?x:y);
}
inline void Max(int &x,const int &y){
x=(x>y?x:y);
}
const int N=6e5+10,M=1e6+10,inf=0x3f3f3f3f;
struct point{
int x,y,t;
int num;
bool tp;//0: query; 1: modify
};
inline bool operator>(const point &a,const point &b){
if(a.x!=b.x)return a.x>b.x;
if(a.y!=b.y)return a.y>b.y;
return a.t>b.t;
}
inline bool operator==(const point &a,const point &b){
return a.x==b.x&&a.y==b.y&&a.t==b.t;
}
ostream& operator<<(ostream &out,point p){
out<<"("<<p.x<<", "<<p.y<<", "<<p.t<<")";
return out;
}
point p[N],tmp[N],P[N];
int ans[N];
inline int lowbit(int x){
return x&-x;
}
int a[M];//BIT,query max(a[1,x])
inline void modify(int x,int val){
if(val==-1){
//clear
for(;x<=M-5;x+=lowbit(x))a[x]=-inf;
}else{
for(;x<=M-5;x+=lowbit(x))Max(a[x],val);
}
}
inline int query(int x){
int ans=-inf;
for(;x>0;x-=lowbit(x))Max(ans,a[x]);
return ans;
}
void calc(int l,int r){
int mid=(l+r)>>1;
point *pa=p+l,*pb=p+mid+1;
point *pr=p+r,*pmid=p+mid,*pend=tmp+r;
//cerr<<"calc "<
for(point *i=tmp+l;i<=pend;++i){
//cerr<<">> "<
if(pb>pr||(pa<=pmid&&*pb>*pa)){
*i=*pa;//sort by x
++pa;
if(i->tp)
modify(i->y,i->x+i->y);
}else{
*i=*pb;//sort by x
++pb;
//cerr<<">> pb++ "<tp<
if(!i->tp){
//if(i->x+i->y-query(i->y)num])
// cerr<y)<
Min(ans[i->num],i->x+i->y-query(i->y));
}
}
}
for(int i=l;i<=mid;i++){
if(p[i].tp)modify(p[i].y,-1);
}
for(int i=l;i<=r;i++){
p[i]=tmp[i];
}
}
void solve(int l,int r){
//cerr<<"solve "<
if(l==r)return;
int mid=(l+r)>>1;
solve(l,mid);
solve(mid+1,r);
calc(l,r);
}
int main(){
int n=getint(),m=getint();
for(int i=0;i<n;i++){
p[i].x=getint()+1;
p[i].y=getint()+1;
p[i].t=i;
p[i].tp=1;
}
int qaq=0;
for(int i=0;i<m;i++){
p[n+i].tp=2-getint();
if(!p[n+i].tp){
p[n+i].num=qaq;
++qaq;
}
p[n+i].x=getint()+1;
p[n+i].y=getint()+1;
p[n+i].t=n+i;
}
for(int i=0;i<=1e6+5;i++){
a[i]=-inf;
}
memset(ans,0x3f,sizeof(ans));
memcpy(P,p,sizeof(P));
//cerr<<"-------1-------"<
solve(0,n+m-1);
//cerr<<"-------2-------"<
for(int i=0;i<n+m;i++){
p[i]=P[i];
p[i].x=M-5-p[i].x;
}
solve(0,n+m-1);
//cerr<<"-------3-------"<
for(int i=0;i<n+m;i++){
p[i]=P[i];
p[i].y=M-5-p[i].y;
}
solve(0,n+m-1);
//cerr<<"-------4-------"<
for(int i=0;i<n+m;i++){
p[i]=P[i];
p[i].x=M-5-p[i].x;
p[i].y=M-5-p[i].y;
}
solve(0,n+m-1);
for(int i=0;i<qaq;i++){
printf("%d\n",ans[i]);
}
return 0;
}