luoguP3769 [CH弱省胡策R2]TATT

luoguP3769 [CH弱省胡策R2]TATT

PS:做这题前先切掉 P4148简单题,对于本人这样的juruo更助于理解,当然dalao就当练练手吧

题目大意: 现在有n个四维空间中的点,请求出一条最长的路径,满足任意一维坐标都是单调不降的

 偏模板的K-D Tree

题目没规定起点,则从任意一点出发,按维度优先级以及每个维度坐标为关键字排序,

每点作为终点查询一次,再插入,其他就是模板化的代码了

这里用到了一个小技巧,就是初始化将子树0的值赋值,避免过多的特判,使代码更加简洁

for(LL i=0;i<=3;++i)
        tree[0].mi[i]=inf,tree[0].mx[i]=-inf; tree[0].maxn=-inf;

My complete code:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long LL;
const LL maxn=1e5+10;
const LL inf=1e9;
inline LL read(){
    LL x=0,f=1; char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-') f=-1; c=getchar();
    }
    while(c>='0'&&c<='9'){
        x=x*10+c-'0'; c=getchar();
    }
    return x*f;
}
struct node{
    LL son[2],d[4],maxn,size,val,mi[4],mx[4];
}tree[maxn],t2[maxn],tmp;
bool operator < (node g1,node g2){
    for(LL i=0;i<=3;++i){
        if(g1.d[i]<g2.d[i]) return 1;
        if(g1.d[i]>g2.d[i]) return 0;
    }return 0;
}
LL n,ans,ans_maxn,top,cnt,root,WD; LL sta[maxn];
inline void update(LL now){
    LL son0=tree[now].son[0],son1=tree[now].son[1];
    for(LL i=0;i<=3;++i){
        tree[now].mi[i]=min(min(tree[son0].mi[i],tree[son1].mi[i]),tree[now].d[i]);
        tree[now].mx[i]=max(max(tree[son0].mx[i],tree[son1].mx[i]),tree[now].d[i]);
    }
    tree[now].maxn=max(tree[now].val,max(tree[son0].maxn,tree[son1].maxn));
    tree[now].size=tree[son0].size+tree[son1].size+1;
}
inline bool cmp(LL g1,LL g2){
    return tree[g1].d[WD]<tree[g2].d[WD];
}
LL build(LL l,LL r,LL wd){
    if(l>r)
        return 0;
    LL mid=(l+r)>>1;
    WD=wd;
    nth_element(sta+l,sta+mid,sta+r+1,cmp);
    LL now=sta[mid];
    tree[now].son[0]=build(l,mid-1,(wd+1)%4);
    tree[now].son[1]=build(mid+1,r,(wd+1)%4);
    update(now);
    return now;
}
void pai(LL now){
    if(!now)
        return;
    sta[++top]=now;
    LL son0=tree[now].son[0],son1=tree[now].son[1];
    pai(son0); pai(son1);
}
inline void check(LL &now,LL wd){
    LL son0=tree[now].son[0],son1=tree[now].son[1];
    if(tree[now].size*0.75<tree[son0].size||tree[now].size*0.75<tree[son1].size){
        top=0;
        pai(now);
        now=build(1,tree[now].size,wd);
    }
}
void insert(LL &now,LL wd){
    if(!now){
        now=++cnt;
        tree[now]=tmp;
        for(LL i=0;i<=3;++i)
            tree[now].mi[i]=tree[now].mx[i]=tree[now].d[i];
        tree[now].maxn=tree[now].val; tree[now].size=1;
        return;
    }
    if(tmp.d[wd]<tree[now].d[wd])
        insert(tree[now].son[0],(wd+1)%4);
    else
        insert(tree[now].son[1],(wd+1)%4);
    update(now);
    check(now,wd);
}

inline LL dis(node g1,node g2){
    for(LL i=0;i<=3;++i) 
        if(g1.d[i]>g2.d[i])
            return 0;
    return g1.val;
}
inline LL into(LL now){
    if(!now)
        return 0;
    LL sum=0;
    for(LL i=0;i<=3;++i)
        if(tree[now].mx[i]<=tmp.d[i])
            ++sum;
    if(sum==4)
        return 4;
    for(LL i=0;i<=3;++i)
        if(tree[now].mi[i]>tmp.d[i])
            return 0;
    return 1;
}
void query(LL now){
    ans=max(dis(tree[now],tmp),ans);
    LL son0=tree[now].son[0],son1=tree[now].son[1];
    LL dl=into(son0),dr=into(son1);
    if(dl==4)
        ans=max(tree[son0].maxn,ans);
    else if(dl&&ans<tree[son0].maxn)
        query(son0);
    if(dr==4)
        ans=max(tree[son1].maxn,ans);
    else if(dr&&ans<tree[son1].maxn)
        query(son1);
}
int main(){
    n=read();
    for(LL i=1;i<=n;++i){
        for(LL j=0;j<=3;++j)
            t2[i].d[j]=read();
        t2[i].val=1;
    }
    sort(t2+1,t2+n+1);
    for(LL i=0;i<=3;++i)
        tree[0].mi[i]=inf,tree[0].mx[i]=-inf; tree[0].maxn=-inf;
    for(LL i=1;i<=n;++i){
        ans=0;
        tmp=t2[i];
        query(root);
        tmp.val+=ans;
        ans_maxn=max(tmp.val,ans_maxn);
        insert(root,0);
    }
    printf("%lld",ans_maxn);
    return 0;
}

  

 

 

 

 

转载于:https://www.cnblogs.com/y2823774827y/p/10072259.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值