洛谷P4169 [Violet]天使玩偶/SJY擺棋子(CDQ分治)
阿新 • • 發佈:2018-12-11
洛谷 P4169 [Violet]天使玩偶/SJY擺棋子
https://www.luogu.org/problemnew/show/P4169
對於曼哈頓距離 考慮四個方向分別求解,因此現在考慮一個方向如何求解
cdq分治時,左邊的修改會對右邊的詢問產生影響,於是使用樹狀陣列維護。那麼具體什麼樣的左邊的點會對右邊造成影響呢?當然是兩個座標都小於等於詢問辣,那麼我們對左邊點進行排序(不用sort,自然歸併即可),對於詢問直接訪問樹狀陣列就行啦。
具體維護的是X+Y的最大值
時間複雜度
這題時間卡的比較緊 區間最值用線段樹會卡掉 所以用樹狀陣列維護
// 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;
}