Jzoj3591 数据
现在,二维平面上有N个点。Alex 需要实现以下三种操作:
1. 在点集里添加一个点;
2. 给出一个点,查询它到点集里所有点的曼哈顿距离的最小值;3. 给出一个点,查询它到点集里所有点的曼哈顿距离的最大值。
两个点的曼哈顿距离定义为它们的横坐标差的绝对值与纵坐标差的绝对值的和。这么困难的问题,Alex当然不会做,只好再次请你帮忙了。
树套树裸题
cdq分治第二题诶,突然才感觉cdq分治好棒啊
分成按照相对询问的坐标四种情况,分别是1234象限,让后分别开两颗线段树分治
注意这样会超时,我们按照x分治,将23象限分到一起分治,14象限分到一起分治,同时开4颗动态开点的线段树以y坐标作为键值,这样可以减小常数,同时也减小代码量
#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<queue>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 100010
#define M 1000000000
#define mid (l+r>>1)
#define LL long long
using namespace std;
int n,m,t=0; LL ans[N];
struct op{ int o,x,y,r; } s[N<<1],c[N<<1],r[N<<1];
struct seg{
int rt,cnt;
struct tree{ int l,r; LL s,m; } s[N<<5];
void clear(){ cnt=rt=0; }
inline void insert(int l,int r,int& x,int p,LL k){
if(!x) s[x=++cnt]=(tree){0,0,-(M<<1),M<<1};
s[x].s=max(s[x].s,k); s[x].m=min(s[x].m,k);
if(l==r) return;
if(p<=mid) insert(l,mid,s[x].l,p,k);
else insert(mid+1,r,s[x].r,p,k);
}
inline LL query(int l,int r,int x,int L,int R){
if(!x) return -(M<<1);
if(L<=l && r<=R) return s[x].s;
LL ans=-(M<<1);
if(L<=mid) ans=max(ans,query(l,mid,s[x].l,L,R));
if(mid<R) ans=max(ans,query(mid+1,r,s[x].r,L,R));
return ans;
}
inline LL Query(int l,int r,int x,int L,int R){
if(!x) return M<<1;
if(L<=l && r<=R) return s[x].m;
LL ans=M<<1;
if(L<=mid) ans=min(ans,Query(l,mid,s[x].l,L,R));
if(mid<R) ans=min(ans,Query(mid+1,r,s[x].r,L,R));
return ans;
}
inline void insert(int p,int k){ insert(0,M,rt,p,k); }
inline LL query(int L,int R){ return query(0,M,rt,L,R); }
inline LL Query(int L,int R){ return Query(0,M,rt,L,R); }
}MX,MS;
void cdq1(int l,int r){
if(l==r) return;
int m=mid,t=l,i,j;
cdq1(l,m); cdq1(m+1,r);
MX.clear();
MS.clear();
for(i=l,j=m+1;i<=m&&j<=r;)
if(s[i].x>=s[j].x){
if(s[i].o==0){
MX.insert(s[i].y,s[i].x+s[i].y);
MS.insert(s[i].y,s[i].x-s[i].y);
}
c[t++]=s[i++];
} else{
if(s[j].o==1) ans[s[j].r]=min(ans[s[j].r],min(MX.Query(s[j].y,M)-s[j].x-s[j].y,MS.Query(0,s[j].y)-s[j].x+s[j].y));
else if(s[j].o==2) ans[s[j].r]=max(ans[s[j].r],max(MX.query(s[j].y,M)-s[j].x-s[j].y,MS.query(0,s[j].y)-s[j].x+s[j].y));
c[t++]=s[j++];
}
for(;i<=m;++i) c[t++]=s[i];
for(;j<=r;++j){
if(s[j].o==1) ans[s[j].r]=min(ans[s[j].r],min(MX.Query(s[j].y,M)-s[j].x-s[j].y,MS.Query(0,s[j].y)-s[j].x+s[j].y));
else if(s[j].o==2) ans[s[j].r]=max(ans[s[j].r],max(MX.query(s[j].y,M)-s[j].x-s[j].y,MS.query(0,s[j].y)-s[j].x+s[j].y));
c[t++]=s[j];
}
for(int i=l;i<=r;++i) s[i]=c[i];
}
void cdq2(int l,int r){
if(l==r) return;
int m=mid,t=l,i,j;
cdq2(l,m); cdq2(m+1,r);
MX.clear();
MS.clear();
for(i=l,j=m+1;i<=m&&j<=r;)
if(s[i].x<=s[j].x){
if(s[i].o==0){
MX.insert(s[i].y,s[i].x+s[i].y);
MS.insert(s[i].y,-s[i].x+s[i].y);
}
c[t++]=s[i++];
} else{
if(s[j].o==1) ans[s[j].r]=min(ans[s[j].r],min(-MX.query(0,s[j].y)+s[j].x+s[j].y,MS.Query(s[j].y,M)+s[j].x-s[j].y));
else if(s[j].o==2) ans[s[j].r]=max(ans[s[j].r],max(-MX.Query(0,s[j].y)+s[j].x+s[j].y,MS.query(s[j].y,M)+s[j].x-s[j].y));
c[t++]=s[j++];
}
for(;i<=m;++i) c[t++]=s[i];
for(;j<=r;++j){
if(s[j].o==1) ans[s[j].r]=min(ans[s[j].r],min(-MX.query(0,s[j].y)+s[j].x+s[j].y,MS.Query(s[j].y,M)+s[j].x-s[j].y));
else if(s[j].o==2) ans[s[j].r]=max(ans[s[j].r],max(-MX.Query(0,s[j].y)+s[j].x+s[j].y,MS.query(s[j].y,M)+s[j].x-s[j].y));
c[t++]=s[j];
}
for(int i=l;i<=r;++i) s[i]=c[i];
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%d%d",&s[i].x,&s[i].y);
scanf("%d",&m);
for(int i=1;i<=m;++i){
scanf("%d%d%d",&s[i+n].o,&s[i+n].x,&s[i+n].y);
if(s[i+n].o) s[i+n].r=++t,ans[t]=(s[i+n].o&1?M<<1:0);
}
memcpy(r,s,sizeof s); cdq1(1,n+m);
memcpy(s,r,sizeof s); cdq2(1,n+m);
for(int i=1;i<=t;++i) printf("%lld\n",ans[i]);
}