洛谷 P4169 [Violet]天使玩偶/SJY摆棋子
https://www.luogu.org/problemnew/show/P4169
对于曼哈顿距离 考虑四个方向分别求解,因此现在考虑一个方向如何求解
cdq分治时,左边的修改会对右边的询问产生影响,于是使用树状数组维护。那么具体什么样的左边的点会对右边造成影响呢?当然是两个坐标都小于等于询问辣,那么我们对左边点进行排序(不用sort,自然归并即可),对于询问直接访问树状数组就行啦。
具体维护的是X+Y的最大值
时间复杂度 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)
这题时间卡的比较紧 区间最值用线段树会卡掉 所以用树状数组维护
// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int n,m;
const int maxn=3e5+10;
const int maxq=maxn<<1;
const int maxm=2e6+10;
const int inf= 0x3f3f3f3f;
int maxid;
int maxx[maxm<<2];
void Pushup(int rt){
maxx[rt]=max(maxx[rt<<1],maxx[rt<<1|1]);
}
void cmax(int &x,int y){
x= x>y? x : y;
}
//
//void build(int l,int r,int rt){
// if(l==r){
// maxx[rt]=-inf;
// return ;
// }
// int m=(l+r)>>1;
// build(lson);build(rson);
// Pushup(rt);
//}
//
//void update(int p,int cov,int l,int r,int rt){
// if(l==r){
// maxx[rt]=cov;
// return ;
// }
// int m=(l+r)>>1;
// if(p<=m) update(p,cov,lson);
// else update(p,cov,rson);
// Pushup(rt);
//}
//
//int query(int L,int R,int l,int r,int rt){
// if(L<=l && r<=R) return maxx[rt];
// int m=(l+r)>>1;
// int ret=-inf;
// if(L<=m) cmax(ret,query(L,R,lson));
// if(R>m) cmax(ret,query(L,R,rson));
// return ret;
//}
int mx[maxm];
int lowbit(int x) { return x&(-x); }
void add(int x,int v){ for(int i=x;i<=maxid;i+=lowbit(i))cmax(mx[i],v);}
int query(int x){ int res=-inf; for(int i=x;i>0;i-=lowbit(i))cmax(res,mx[i]); return res;}
void cls(int x){ for(int i=x;i<=maxid;i+=lowbit(i))mx[i]=-inf;}
struct node{
int x,y;
int type;
int id;
bool operator < (const node & rhs) const{
return x == rhs.x ? y<= rhs.y : x <= rhs.x ;
}
}no[maxq];
int ans[maxq];
node tmp[maxq];
node tmp2[maxq];
void cdq(int L,int R)
{
if(L==R) return ;
int M=(L+R)>>1;
cdq(L,M);cdq(M+1,R);
int l=L,r=M+1;
int tid=1;
while(l<=M && r<=R){
if(no[l]<no[r]){
if(no[l].type==1){
//update(no[l].y,no[l].y+no[l].x,1,maxid,1);
add(no[l].y,no[l].x+no[l].y);
}
tmp[tid++]=no[l++];
}
else{
// cout<<query(1,no[r].y,1,maxid,1)<<endl;
if(no[r].type==2) {
//ans[no[r].id]=min(ans[no[r].id],no[r].x+no[r].y-query(1,no[r].y,1,maxid,1));
ans[no[r].id]=min(ans[no[r].id],no[r].x+no[r].y-query(no[r].y));
}
tmp[tid++]=no[r++];
}
}
while(l<=M){
tmp[tid++]=no[l++];
}
while(r<=R){
if(no[r].type==2){
//ans[no[r].id]=min(ans[no[r].id],no[r].x+no[r].y-query(1,no[r].y,1,maxid,1));
ans[no[r].id]=min(ans[no[r].id],no[r].x+no[r].y-query(no[r].y));
}
tmp[tid++]=no[r++];
}
for(int i=L;i<=M;++i){
if(no[i].type==1) {
//update(no[i].y,-inf,1,maxid,1);
cls(no[i].y);
}
}
for(int i=L;i<=R;++i) no[i]=tmp[i-L+1];
}
int main()
{
// freopen("in.txt","r",stdin);
maxid=0;
memset(mx,-inf,sizeof(mx));
int idx=1;
int aid=1;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i){
scanf("%d%d",&no[idx].x,&no[idx].y);
no[idx].x++;
no[idx].y++;
maxid=max(maxid,no[idx].x);
maxid=max(maxid,no[idx].y);
no[idx++].type=1;
}
for(int i=1;i<=m;++i){
int type;
scanf("%d",&type);
if(type==1){
no[idx].type=1;
scanf("%d%d",&no[idx].x,&no[idx].y);
no[idx].x++;
no[idx].y++;
maxid=max(maxid,no[idx].x);
maxid=max(maxid,no[idx].y);
idx++;
}
else{
no[idx].type=2;
scanf("%d%d",&no[idx].x,&no[idx].y);
no[idx].x++;
no[idx].y++;
maxid=max(maxid,no[idx].x);
maxid=max(maxid,no[idx].y);
no[idx].id=aid;
aid++;
idx++;
}
}
for(int i=1;i<idx;++i) tmp2[i]=no[i];
for(int i=1;i<aid;++i) ans[i]=inf;
maxid+=1;
//build(1,maxid,1);
cdq(1,idx-1);
for(int i=1;i<idx;++i) tmp2[i].x=maxid-tmp2[i].x,no[i]=tmp2[i];
cdq(1,idx-1);
for(int i=1;i<idx;++i) tmp2[i].y=maxid-tmp2[i].y,no[i]=tmp2[i];
cdq(1,idx-1);
for(int i=1;i<idx;++i) tmp2[i].x=maxid-tmp2[i].x,no[i]=tmp2[i];
cdq(1,idx-1);
for(int i=1;i<aid;++i){
printf("%d\n",ans[i]);
}
return 0;
}