1. 程式人生 > >洛谷P4169 [Violet]天使玩偶/SJY擺棋子(CDQ分治)

洛谷P4169 [Violet]天使玩偶/SJY擺棋子(CDQ分治)

洛谷 P4169 [Violet]天使玩偶/SJY擺棋子

https://www.luogu.org/problemnew/show/P4169

對於曼哈頓距離 考慮四個方向分別求解,因此現在考慮一個方向如何求解

cdq分治時,左邊的修改會對右邊的詢問產生影響,於是使用樹狀陣列維護。那麼具體什麼樣的左邊的點會對右邊造成影響呢?當然是兩個座標都小於等於詢問辣,那麼我們對左邊點進行排序(不用sort,自然歸併即可),對於詢問直接訪問樹狀陣列就行啦。

img

img

具體維護的是X+Y的最大值

時間複雜度 O

( n l o g 2 n ) O(nlog^2n)

這題時間卡的比較緊 區間最值用線段樹會卡掉 所以用樹狀陣列維護

// 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; }