1. 程式人生 > 實用技巧 >luogu P4169 [Violet]天使玩偶/SJY擺棋子

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

題面傳送門
考慮怎麼把絕對值拆掉。
可以把座標系旋轉四次然後統計左上方的點,這樣可以拆掉絕對值。那麼就是要找左上方\(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');
}