RT
#include<bits/stdc++.h>
#define ll long long
using namespace std;
long long read(){
long long x=0,f=1;char ch=getchar();
while(!isdigit(ch))
{if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
void write(long long x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
const int N=5e4+10;
int n,m;
const int DE=4;//3维
int nde=0,L[DE],R[DE];
struct Node{
int fi;
int w[DE],val;
}s[N];
bool cmp(int p,int q){
return s[p].w[nde]==s[q].w[nde]?p<q:s[p].w[nde]<s[q].w[nde];
}
#define ls(p) a[p].tl
#define rs(p) a[p].tr
struct KD{
const double A=0.725;
int rt,tot,g[N],ans;
struct Tree{
int tl,tr,de,sz;
int l[DE],r[DE],mx;
}a[N];
void dfs(int p){
if(ls(p))dfs(ls(p));
g[++tot]=p;
if(rs(p))dfs(rs(p));
}
void update(int p,int son,int de){
a[p].l[de]=min(a[p].l[de],a[son].l[de]);
a[p].r[de]=max(a[p].r[de],a[son].r[de]);
}
void pushup(int p){
a[p].sz=a[ls(p)].sz+a[rs(p)].sz+1;
a[p].mx=max(s[p].val,max(a[ls(p)].mx,a[rs(p)].mx));
for(register int i=1;i<DE;i++)a[p].l[i]=a[p].r[i]=s[p].w[i];
if(ls(p))for(register int i=1;i<DE;i++)update(p,ls(p),i);
if(rs(p))for(register int i=1;i<DE;i++)update(p,rs(p),i);
}
double fangc(int l,int r,int de){
double av=0,sa=0;
for(register int i=l;i<=r;i++)av+=s[g[i]].w[de];
av/=double(r-l+1);
for(register int i=l;i<=r;i++)
sa+=(av-s[g[i]].w[de])*(av-s[g[i]].w[de]);
return sa;
}
int build(int l,int r){
if(l>r)return 0;
int p=(l+r)>>1;
double fcm=1e18,fc;
nde=0;
/*for(register int i=1;i<DE;i++){
fc=fangc(l,r,i);
if(!nde||fcm>fc)
nde=i,fcm=fc;
}*/
nde=(nde+1)%3+1;
nth_element(g+l,g+p,g+r+1,cmp);
a[g[p]].de=nde;
ls(g[p])=build(l,p-1);rs(g[p])=build(p+1,r);
pushup(g[p]);return g[p];
}
void rebuild(int &p){
tot=0;dfs(p);p=build(1,tot);
}
bool bad(int p){
return a[p].sz*A<=(double)max(a[ls(p)].sz,a[rs(p)].sz);
}
void insert(int &p,int x){
if(!p){
pushup(p=x);return;
}
if(s[x].w[a[p].de]==s[p].w[a[p].de]?x<p:s[x].w[a[p].de]<s[p].w[a[p].de])
insert(ls(p),x);
else insert(rs(p),x);
pushup(p);
if(bad(p))rebuild(p);
}
void query(int p,int *l,int *r){
if(!p)return;
if(a[p].mx<=ans)return;
bool flag1=1,flag2=1;
/*for(register int i=1;i<DE;i++){
if(r[i]<a[p].l[i]||a[p].r[i]<l[i])return;
if(r[i]<a[p].r[i]||a[p].l[i]<l[i])flag1=0;
if(r[i]<s[p].w[i]||s[p].w[i]<l[i])flag2=0;
}
if(flag1){
ans=max(ans,a[p].mx);
return;
}
ans=max(ans,flag2*s[p].val);*/
if(r[1]<a[p].l[1]||r[2]<a[p].l[2]||r[3]<a[p].l[3])
return;
if(r[1]>=a[p].r[1]&&r[2]>=a[p].r[2]&&r[3]>=a[p].r[3]){
ans=max(ans,a[p].mx);return;
}
if(r[1]>=s[p].w[1]&&r[2]>=s[p].w[2]&&r[3]>=s[p].w[3]){
ans=max(ans,s[p].val);
}
if(ans<a[ls(p)].mx)
query(ls(p),l,r);
if(ans<a[rs(p)].mx)
query(rs(p),l,r);
return;
}
void change(int p,int x,int val){
if(p==x){
s[p].val=val;
a[p].mx=max(a[p].mx,s[p].val);return;
}
if(s[x].w[a[p].de]==s[p].w[a[p].de]?x<p:s[x].w[a[p].de]<s[p].w[a[p].de])
change(ls(p),x,val);
else change(rs(p),x,val);
a[p].mx=max(a[p].mx,max(a[ls(p)].mx,a[rs(p)].mx));
}
}kd;
bool cmp2(Node x,Node y){
return x.fi==y.fi?(x.w[1]==y.w[1]?(x.w[2]==y.w[2]?x.w[3]<y.w[3]:x.w[2]<y.w[2]):x.w[1]<y.w[1]):x.fi<y.fi;
}
int main(){
n=read();
for(register int i=1;i<=n;i++){
s[i].fi=read();
for(register int j=1;j<DE;j++)
s[i].w[j]=read();
}
sort(s+1,s+n+1,cmp2);
for(register int i=1;i<=n;i++)
kd.g[i]=i;
kd.rt=kd.build(1,n);
int ans=0;
for(register int j=1;j<DE;j++)L[j]=-1e9;
for(register int i=1;i<=n;i++){
kd.ans=0;
for(register int j=1;j<DE;j++)
R[j]=s[i].w[j];
kd.query(kd.rt,L,R);
ans=max(ans,kd.ans+1);
kd.change(kd.rt,i,kd.ans+1);
}
write(ans);
return 0;
}
有个很神奇的事情,把 query 和 change 去掉一个就不会T,只会WA