【题解】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;
}

浙公网安备 33010602011771号