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

P4169】题解

一:【题意】

二:【解法】

每个点有属性{t,a,b}表{时间,x坐标,y坐标}
每次只考虑以i为原点的第三象限
等价于求多少点j满足t[j]<=t[i],x[j]<=x[i],y[j]<=y[i]
然后旋转90度分别处理再累加即可

三:【代码】

#include<bits/stdc++.h>
#define inf 1e9
using namespace std;
const int N=6e5+10,M=1e6+10;
struct node{
	int op;
	int t,a,b;
	int ans;
}q[N];
bool cmpt(node x,node y){
	if(x.t!=y.t) return x.t<y.t;
	if(x.a!=y.a) return x.a<y.a;
	return x.b<y.b;
}
bool cmpa(node x,node y){
	return x.a<y.a;
}
int tree[M];
void update(int x,int d){
	while(x<M){
		tree[x]=max(tree[x],d);
		x+=x&-x;
	}
}
int query(int x){
	int res=-inf;
	while(x){
		res=max(res,tree[x]);
		x-=x&-x;
	}
	return res;
}
void clear(int x){
	while(x<M){
		tree[x]=-inf;
		x+=x&-x;
	}
}
void CDQ(int l,int r){
	if(l==r) return ;
	int mid=l+r>>1;
	CDQ(l,mid);CDQ(mid+1,r);
	sort(q+l,q+mid+1,cmpa);sort(q+mid+1,q+r+1,cmpa);
	int i=l,j=mid+1;
	while(j<=r){
		while(i<=mid&&q[i].a<=q[j].a){
			if(q[i].op==1) update(q[i].b,q[i].a+q[i].b);
			i++;
		}
		if(q[j].op==2) q[j].ans=min(q[j].ans,q[j].a+q[j].b-query(q[j].b));
		j++;
	}
	for(int k=l;k<i;k++){
		if(q[k].op==1) clear(q[k].b);
	}
}
int ok[N],as[N];
int main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	int n,m;cin>>n>>m;
	int idx=0;
	while(n--){
		int x,y;cin>>x>>y;
		x++;y++;
		q[++idx]={1,0,x,y,(int)inf};
	}
	for(int i=1;i<M;i++) tree[i]=-inf;
	for(int i=1;i<=m;i++){
		int op,x,y;cin>>op>>x>>y;
		x++;y++;
		q[++idx]={op,i,x,y,(int)inf};
		if(op==2) ok[i]=1;
	}
	for(int i=1;i<=4;i++){
		sort(q+1,q+1+idx,cmpt);
		CDQ(1,idx);
		for(int i=1;i<=idx;i++){
			swap(q[i].a,q[i].b);
			q[i].a=M-q[i].a-1;
			
			//q[i].a=q[i].a;
			//q[i].b=-q[i].b;
		}
	}
	for(int i=1;i<=idx;i++) as[q[i].t]=q[i].ans;
	for(int i=1;i<=m;i++){
		if(ok[i]) cout<<as[i]<<"\n";
	}
	return 0;
}
posted @ 2025-12-27 09:31  Ming3398  阅读(2)  评论(0)    收藏  举报