luogu P4169 [Violet]天使玩偶/SJY擺棋子
阿新 • • 發佈:2021-01-10
題面傳送門
考慮怎麼把絕對值拆掉。
可以把座標系旋轉四次然後統計左上方的點,這樣可以拆掉絕對值。那麼就是要找左上方\(x+y\)最小的點,變成三維偏序問題。
可以用\(cdq\)分治輕鬆解決。
注意這道題卡常,可以嘗試把\(cdq\)中的快排換成歸併能快好幾倍。
同時只對詢問查詢。
時間複雜度\(O(nlog^2n)\)常數很小。
程式碼實現:
#include<cstdio> #include<algorithm> #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) using namespace std; int n,m,k,xs,ys,zs,f[1000039],now; struct yyy{int x,y,id,z,tim,w;}s[1000039],b[1000039]; inline bool cmp1(yyy x,yyy y){return x.x<y.x;} inline bool cmp2(yyy x,yyy y){return x.tim<y.tim;} inline void get(int x,int y){while(x<=zs) f[x]=max(f[x],y),x+=x&-x;} inline int find(int x){int ans=0;while(x) ans=max(ans,f[x]),x-=x&-x;return ans;} inline void clear(int x){while(x<=zs&&f[x]) f[x]=0,x+=x&-x;} inline void slove(int x,int y){ if(x==y) return; int m=x+y>>1,l=x,i,head=x-1; slove(x,m);slove(m+1,y); for(i=m+1;i<=y;i++){ //if(s[i].id==1) continue; while(l<=m&&s[l].x<=s[i].x){ if(s[l].id==1)get(s[l].y,s[l].x+s[l].y); b[++head]=s[l++]; } if(s[i].id==2){ now=find(s[i].y); if(now)s[i].w=min(s[i].w,s[i].x+s[i].y-now); }b[++head]=s[i]; } while(l<=m) b[++head]=s[l++]; for(i=x;i<l;i++) clear(s[i].y); for(i=x;i<=y;i++) s[i]=b[i]; } inline void read(int &x){ char s=getchar();x=0; while(s<'0'||s>'9') s=getchar(); while(s>='0'&&s<='9') x=x*10+s-48,s=getchar(); } inline void print(int x){ if(x>9) print(x/10); putchar(x%10+48); } int main(){ freopen("1.in","r",stdin); freopen("1.out","w",stdout); register int i; scanf("%d%d",&n,&m); for(i=1;i<=n;i++)read(s[i].x),read(s[i].y),s[i].x++,s[i].y++,s[i].id=1,s[i].tim=i,xs=max(xs,s[i].x),ys=max(ys,s[i].y); for(i=n+1;i<=m+n;i++)read(s[i].id),read(s[i].x),read(s[i].y),s[i].x++,s[i].y++,s[i].w=1e9,s[i].tim=i,xs=max(xs,s[i].x),ys=max(ys,s[i].y); zs=max(xs,ys)+2;n+=m; slove(1,n); sort(s+1,s+n+1,cmp2); for(i=1;i<=n;i++) s[i].x=zs-s[i].x; slove(1,n); sort(s+1,s+n+1,cmp2); for(i=1;i<=n;i++) s[i].y=zs-s[i].y; slove(1,n); sort(s+1,s+n+1,cmp2); for(i=1;i<=n;i++) s[i].x=zs-s[i].x; slove(1,n); sort(s+1,s+n+1,cmp2); for(i=1;i<=n;i++) if(s[i].id==2) print(s[i].w),putchar('\n'); }