把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

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');
}
posted @ 2021-01-09 20:29  275307894a  阅读(56)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end