题解 P4169 【[Violet]天使玩偶/SJY摆棋子】

题解 - P 4196 \mathrm{P4196} P4196

题目意思

题目传送门

S o l \mathrm{Sol} Sol

一道cdq分治好题

我们首先考虑离线下来做,对于一次询问操作点 ( x , y ) (x,y) (x,y) 以及要找与其配对得最近点 ( x ′ , y ′ ) (x',y') (x,y),其间的距离 D = ∣ x − x ′ ∣ + ∣ y − y ′ ∣ D=|x-x'|+|y-y'| D=xx+yy 很显然带着绝对值不好处理,我们考虑去掉。

于是我们想到了一个有效的方法,即假设 ( x ′ , y ′ ) (x',y') (x,y) 都在 ( x , y ) (x,y) (x,y) 的左下角,即满足 x ′ ≤ x , y ′ ≤ y x'\leq x,y'\leq y xx,yy 然后要使得 x + y − ( x ′ + y ′ ) x+y-(x'+y') x+y(x+y) 最小即要求 x ′ + y ′ x'+y' x+y最大。那么就是经典三维偏序问题,我们可以用cdq来解决。

那么我们分别对于询问点在器左上,左下,右上,右下分别做一遍即可。

时间复杂度 O ( 4 × n × log ⁡ 2 max ⁡ ( x i , y i ) ) O(4\times n\times\log^2 \max(x_i,y_i)) O(4×n×log2max(xi,yi))

我们为了不被卡常需要把cdq里面的排序换成归并来处理即可。

C o d e \mathrm{Code} Code


const int M=1e7+5;
const int N=1e6+5;

int n,m,mx,C[M];

struct Node
{
	int type,x,y,id,ans;
};
Node a[N],b[N],c[N];

inline void Add(int x,int v)
{
	if(x<=0) return;
	while(x<=mx)
	{
		C[x]=max(C[x],v);
		x+=lowbit(x);
	}
}

inline int Ask(int x)
{
	if(x<=0) return 0;
	int ans=0;
	while(x)
	{
		ans=max(ans,C[x]);
		x-=lowbit(x);
	}
	return (ans)?ans:-1000000000;
}

inline void Clear(int x)
{
	if(x<=0) return;
	while(x<=mx)
	{
		C[x]=0;
		x+=lowbit(x);
	}
}

inline 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;
	int gs=l;
	while(R<=r) 
	{
		while(L<=mid&&b[L].x<=b[R].x) 
		{
			if(b[L].type==1) Add(b[L].y,b[L].x+b[L].y);
			c[gs++]=b[L++]; 
		}
		if(b[R].type==2) a[b[R].id].ans=min(a[b[R].id].ans,b[R].x+b[R].y-Ask(b[R].y));
		c[gs++]=b[R++];
	}
	For(k,l,L-1) if(b[k].type==1) Clear(b[k].y);
	while(L<=mid) c[gs++]=b[L++];
	For(i,l,r) b[i]=c[i];
}

inline void solve(int opx,int opy)
{
	For(i,1,n+m) 
	{
		b[i]=a[i];
		if(opx) b[i].x=mx-b[i].x;
		if(opy) b[i].y=mx-b[i].y;
	}
	cdq(1,n+m);
}

int main()
{
	io.read(n),io.read(m);
	For(i,1,n)
	{
		int x,y;
		io.read(x),io.read(y);
		a[i].type=1;
		a[i].x=x+1,a[i].y=y+1;
		mx=max(max(x+1,y+1),mx);
		a[i].id=i;
	}
	For(i,n+1,n+m)
	{
		int x,y,type;
		io.read(type),io.read(x),io.read(y);
		a[i].type=type;
		a[i].x=x+1,a[i].y=y+1;
		a[i].ans=1e9;
		mx=max(max(x+1,y+1),mx);
		a[i].id=i;
	}
	mx++;
	For(i,0,1) For(j,0,1) solve(i,j);
	int ask=0;
	For(i,n+1,n+m) if(a[i].type==2) 
		io.write(a[i].ans),putchar('\n');
	return 0;
}

你可能感兴趣的:(树状数组,cdq)