1. 程式人生 > >[Luogu4169][Violet]天使玩偶/SJY擺棋子

[Luogu4169][Violet]天使玩偶/SJY擺棋子

string set del 最大值 href 前綴 query ring 樹狀

luogu

題意

一個平面上有\(n\)個點,\(m\)次操作,每次新增一個點,或者是詢問離某個點最近的點的距離。這裏的距離是曼哈頓距離。
\(n,m\le3*10^5\)

sol

寫一發\(CDQ\)
只考慮詢問點在其他點的右上方的情況,假設詢問點是\(A\),那麽所求的距離就是\((X_A-X_i)+(Y_A-Y_i)=(X_A+Y_A)-(X_i+Y_i)\)
所以我們只需要找出滿足\(X_i \le X_A,Y_i \le Y_A\)\(X_i+Y_i\)的最大值就好了。
\(CDQ\)前先按時間戳排序,向上歸並時按\(X\)排序。考慮左邊對右邊的貢獻時,按\(Y\)值為下標插入樹狀數組,然後查詢前綴最大值。

對於不在右上方的情況,只要把坐標軸翻轉四次就可以了。





然而。
這題卡常。
以下是一些卡常技巧。

清空樹狀數組的時候,如果當前位已經是\(0\)就直接\(return\)
預先記錄按照時間戳的排序,每次\(CDQ\)完後直接復制一遍,不需要排序。
刪除不必要的點(不會被任何詢問考慮到的點)

常數巨大無比。

code

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int gi()
{
    int x=0,w=1;char ch=getchar();
    while
((ch<'0'||ch>'9')&&ch!='-') ch=getchar(); if (ch=='-') w=0,ch=getchar(); while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return w?x:-x; } const int N = 1e6+5; struct node{ int tim,opt,x,y; bool
operator < (const node &b) const { if (x!=b.x) return x<b.x; if (y!=b.y) return y<b.y; return opt<b.opt; } }a[N],p[N],q[N]; int n,m,X,Y,c[N],ans[N]; inline void modify(int k,int v){while(k<=Y)c[k]=max(c[k],v),k+=k&-k;} inline int query(int k){int s=0;while(k)s=max(s,c[k]),k-=k&-k;return s;} inline void clear(int k){while(k<=Y)if(c[k])c[k]=0,k+=k&-k;else return;} void CDQ(int l,int r) { if (l==r) return; int mid=l+r>>1;CDQ(l,mid);CDQ(mid+1,r); int L=l,R=mid+1; for (int i=l;i<=r;++i) if (L<=mid&&(R>r||p[L]<p[R])) { q[i]=p[L++]; if (q[i].opt==1) modify(q[i].y,q[i].x+q[i].y); } else { q[i]=p[R++]; if (q[i].opt==2) { int tmp=query(q[i].y); if (tmp) ans[q[i].tim]=min(ans[q[i].tim],q[i].x+q[i].y-tmp); } } for (int i=l;i<=r;++i) p[i]=q[i],clear(p[i].y); } void Delete() { int xx=0,yy=0;m=0; for (int i=1;i<=n;++i) if (p[i].opt==2) xx=max(xx,p[i].x),yy=max(yy,p[i].y); for (int i=1;i<=n;++i) if (p[i].x<=xx&&p[i].y<=yy) q[++m]=p[i]; for (int i=1;i<=m;++i) p[i]=q[i]; } int main() { n=gi();m=gi();memset(ans,63,sizeof(ans)); for (int i=1;i<=n;++i) { a[i]=(node){0,1,gi()+1,gi()+1}; X=max(X,a[i].x);Y=max(Y,a[i].y); } for (int i=1;i<=m;++i) { a[++n]=(node){i,gi(),gi()+1,gi()+1}; X=max(X,a[n].x);Y=max(Y,a[n].y); } ++X;++Y; for (int i=1;i<=n;++i) p[i]=a[i]; Delete();CDQ(1,m); for (int i=1;i<=n;++i) p[i]=a[i],p[i].x=X-p[i].x; Delete();CDQ(1,m); for (int i=1;i<=n;++i) p[i]=a[i],p[i].y=Y-p[i].y; Delete();CDQ(1,m); for (int i=1;i<=n;++i) p[i]=a[i],p[i].x=X-p[i].x,p[i].y=Y-p[i].y; Delete();CDQ(1,m); for (int i=1;i<=n;++i) if (a[i].opt==2) printf("%d\n",ans[a[i].tim]); return 0; }

[Luogu4169][Violet]天使玩偶/SJY擺棋子