请教 解题报告
题目描述
期末考就快到了,每个人都想用最少的努力通近考试,然而这不容易。Alice 认识到最好去请教一些成绩比他好的,每个人都想这么做。
我们规定一个学生成统的好坏用两个整数A和B来表示,A表示对功课的理解力,B表示知识面。
作为班长,Alice规定去请教的这个学生的理解力不得低于自己的理解力,同样知识面也不得低于自己的知识面,在这个基础上选择一个知识面 (B 值)跟自己差距最小的,如果还有多种选择,则在此基础上选择一个理解力( A 值)跟自己差距最小的。
该学校不断有学生转进来,这给每个人的选择带来困难,现在请你来帮忙。
简要题意
有 \(m\) 次操作,每次操作分为两种:
-
加入一个新点 \((x,y)\)。
-
对于一个已经被加入的点 \((x,y)\) 进行询问:找出一个异于 \((x,y)\) 的点 \((a,b)\) 满足 \(a \ge x, b\ge y\) 且 \((a,b)\) 是满足条件的点中 \(b\) 最小的前提下 \(a\) 最小的。
其中,\(m\le 2 \times 10^5\), \(1 \le x,y \le 2 \times 10^9\)
分析
典型的三维偏序问题,考虑 CDQ 分治。
本题难点在于询问时会询问到自己并且自己是不能被统计的。不考虑当前点的询问直接套 CDQ 有点棘手。
考虑拆询问:具体地,我们发现 \((x,y)\) 在不考虑自己的答案,等价于 \((x+1,y)\) 和 \((x,y+1)\) 考虑自己的答案的并集。
如此以来便可以解决问题。
代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define Inf (1ll<<60)
#define For(i,s,t) for(int i=s;i<=t;++i)
#define Down(i,s,t) for(int i=s;i>=t;--i)
#define ls (i<<1)
#define rs (i<<1|1)
#define bmod(x) ((x)>=mod?(x)-mod:(x))
#define lowbit(x) ((x)&(-(x)))
#define End {printf("NO\n");exit(0);}
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
inline void ckmx(int &x,int y){x=(x>y)?x:y;}
inline void ckmn(int &x,int y){x=(x<y)?x:y;}
inline void ckmx(ll &x,ll y){x=(x>y)?x:y;}
inline void ckmn(ll &x,ll y){x=(x<y)?x:y;}
inline int min(int x,int y){return x<y?x:y;}
inline int max(int x,int y){return x>y?x:y;}
inline ll min(ll x,ll y){return x<y?x:y;}
inline ll max(ll x,ll y){return x>y?x:y;}
inline int read(){
register int x=0,f=1;
char c=getchar();
while(c<'0' || '9'<c) f=(c=='-')?-1:1,c=getchar();
while('0'<=c && c<='9') x=(x<<1)+(x<<3)+c-'0',c=getchar();
return x*f;
}
void write(int x){
if(x>=10) write(x/10);
putchar(x%10+'0');
}
const int N=6e5+100;
int n,m,rk[N],cnt,lenx,leny,ans[N];
char s[5];
/*void add(int x){
for(;x<=n;x+=lowbit(x))
++c[x];
}
int ask(int x){
int res=0;
for(;x;x-=lowbit(x))
res+=c[x];
return res;
}*/
struct Node{int x,y,id;}a[N];
bool cmp(Node x,Node y){return x.y^y.y ? x.y>y.y : x.x>y.x;}
struct Act{int opt,ind,tim;}q[N<<1],b[N];
struct Tree{int l,r,tag;pii val;}t[N<<2];
void push_up(int i){
if(t[ls].val.first<=t[rs].val.first)
t[i].val=t[ls].val;
else
t[i].val=t[rs].val;
}
void push_down(int i){
if(t[i].tag){
t[ls].val=t[rs].val=make_pair(inf,0);
t[ls].tag=t[rs].tag=1;
t[i].tag=0;
}
}
void build(int i,int l,int r){
t[i].l=l,t[i].r=r,t[i].val=make_pair(inf,0);
if(l==r) return;
int mid=l+r>>1;
build(ls,l,mid);
build(rs,mid+1,r);
}
void update(int i,int x,pii k){
if(t[i].l==t[i].r){
t[i].val=k;
return;
}
push_down(i);
int mid=t[i].l+t[i].r>>1;
if(x<=mid)
update(ls,x,k);
else
update(rs,x,k);
push_up(i);
}
pii query(int i,int l,int r){
if(l>r) return make_pair(inf,0);
if(l<=t[i].l && t[i].r<=r)
return t[i].val;
push_down(i);
int mid=t[i].l+t[i].r>>1;
pii res1,res2;
if(l>mid) return query(rs,l,r);
if(mid>=r) return query(ls,l,r);
res1=query(ls,l,r),res2=query(rs,l,r);
if(res1.first<=res2.first) return res1;
return res2;
}
void init(){
For(i,1,n) rk[i]=a[i].x;
sort(rk+1,rk+n+1);
lenx=unique(rk+1,rk+n+1)-rk-1;
For(i,1,n) a[i].x=lower_bound(rk+1,rk+lenx+1,a[i].x)-rk;
For(i,1,n) rk[i]=a[i].y;
sort(rk+1,rk+n+1);
leny=unique(rk+1,rk+n+1)-rk-1;
For(i,1,n) a[i].y=lower_bound(rk+1,rk+leny+1,a[i].y)-rk;
}
void solve(int l,int r){
if(l==r) return;
int mid=l+r>>1;
solve(l,mid);
solve(mid+1,r);
int ind=l,ind1=l;
//For(i,l,r) printf("(%d,%d) ",q[i].opt,q[i].ind);
//putchar('\n');
For(i,mid+1,r){
while(ind<=mid && a[q[ind].ind].y>=a[q[i].ind].y){
if(!q[ind].opt){
update(1,a[q[ind].ind].x,make_pair(a[q[ind].ind].y,q[ind].ind));
}
b[ind1]=q[ind];
++ind,++ind1;
}
if(q[i].opt){
int res=query(1,a[q[i].ind].x,lenx).second;
ans[q[i].tim]=(res && (ans[q[i].tim]==-1 || cmp(a[ans[q[i].tim]],a[res]))) ? res : ans[q[i].tim];
}
b[ind1]=q[i];
++ind1;
}
t[1].tag=1,t[1].val=make_pair(inf,0);
while(ind<=mid) b[ind1]=q[ind],++ind1,++ind;
For(i,l,r) q[i]=b[i];
}
int main()
{
//#if !ONLINE_JUDGE
freopen("ispiti.in","r",stdin);
freopen("ispiti.out","w",stdout);
//#endif
m=read();
int x,y,cnt=0,T=0;
For(i,1,m){
scanf("%s",s+1);
if(s[1]=='D')
x=read(),y=read(),a[++n]=(Node){x,y,n},a[++n]=(Node){x+1,y,n},a[++n]=(Node){x,y+1,n},q[++cnt]=(Act){0,n-2,0};
else{
++T;
x=read();
q[++cnt]=(Act){1,x*3-1,T*2-1},q[++cnt]=(Act){1,x*3,T*2};
ans[T*2]=-1,ans[T*2-1]=-1;
}
}
init();
build(1,1,lenx);
solve(1,cnt);
For(i,1,T)
if(ans[i*2-1]!=-1 && ans[i*2]!=-1)
printf("%d\n",cmp(a[ans[i*2]],a[ans[i*2-1]]) ? (ans[i*2-1]-1)/3+1 : (ans[i*2]-1)/3+1);
else if(ans[i*2-1]==-1 && ans[i*2]==-1)
printf("NE\n");
else if(ans[i*2-1]==-1)
printf("%d\n",(ans[i*2]-1)/3+1);
else
printf("%d\n",(ans[i*2-1]-1)/3+1);
return 0;
}