BZOJ 4553 HEOI 2016 seq

本文介绍了一种使用KD树解决偏序关系问题的方法,通过构造KD树并利用其特性来快速查找满足条件的最大值,适用于算法竞赛及数据结构学习。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

用max[i]代表i位置变化最大值,min[i]代表i位置变化最小值
搞出偏序关系,j<=i, max[j] <=a[i], a[j] <= min[i]
这里用的是KDtree求偏序。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1000100;
struct node
{
    int d[2],mx[2],mn[2],l,r,val,mxv;
    int & operator [](int x){return d[x];}
    node (int x=0,int y=0,int z=0)
    {
        d[0]=x;d[1]=y;val=z;l=0;r=0;
    }
} p[maxn];
int n,m,D;
int mx[maxn],mn[maxn],a[maxn],f[maxn],x,y;
bool operator < (node a,node b)
{
    return a[D]<b[D]||(a[D]==b[D]&&a[!D]<b[!D]);
}
int root,res,cnt; 
struct kd_tree
{
    node t;
    void update(int x)
    {
        node l=p[p[x].l],r=p[p[x].r];
        for(int i=0;i<2;i++)
        {
            p[x].mn[i]=p[x].mx[i]=p[x][i];
            if(p[x].l) p[x].mn[i]=min(p[x].mn[i],l.mn[i]),p[x].mx[i]=max(p[x].mx[i],l.mx[i]);
            if(p[x].r) p[x].mn[i]=min(p[x].mn[i],r.mn[i]),p[x].mx[i]=max(p[x].mx[i],r.mx[i]);
        }
        p[x].mxv=max(p[x].val,max(l.mxv,r.mxv));
    }
    int build(int l,int r,int now){
        if(l>r) return 0;
        D=now;
        int mid=(l+r)>>1;
        nth_element(p+l,p+mid,p+r+1);
        p[mid].l=build(l,mid-1,now^1);
        p[mid].r=build(mid+1,r,now^1);
        update(mid);
        return mid;
    }
    void insert(int &x,bool d){
        if(!x){
            x=++cnt;
            p[x][0]=t[0],p[x][1]=t[1];
        }
        if(t[0]==p[x][0]&&t[1]==p[x][1]){
            p[x].val=max(p[x].val,t.val);
            p[x].mxv=max(p[x].mxv,t.val);
            return;
        }
        D=d;
        if(t<p[x]) insert(p[x].l,!d);
        else insert(p[x].r,!d);
        update(x);
    }
    bool in(int x,int y,int X,int Y){return x<=X&&y<=Y;}
    bool out(int x,int y,int X,int Y){return x>X||y>Y;}
    int query(int x,int xm,int ym){
        if(!x) return 0;
        if(in(p[x].mx[0],p[x].mx[1],xm,ym)) return p[x].mxv;
        if(out(p[x].mn[0],p[x].mn[1],xm,ym)) return 0;
        int ans=-1,ans1=-1;
        if(in(p[x][0],p[x][1],xm,ym)) ans=p[x].val;
        if(p[p[x].l].mxv>ans) ans1=query(p[x].l,xm,ym);
        ans=max(ans,ans1);ans1=-1;
        if(p[p[x].r].mxv>ans) ans1=query(p[x].r,xm,ym);
        ans=max(ans,ans1);
        return ans;
    }
    void work(){
        cnt=n;
        for(int i=1;i<=n;i++) p[i]=node(mx[i],a[i],0);
        root=build(0,n,0);
        for(int i=1;i<=n;i++)
        {
            f[i]=query(root,a[i],mn[i])+1;
            t=node(mx[i],a[i],f[i]);
            insert(root,0);
            if(res<f[i]) res=f[i]; 
        }
        printf("%d\n",res);
    }
}kd;
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        mx[i]=mn[i]=a[i];
    } 
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        mx[x]=max(mx[x],y);
        mn[x]=min(mn[x],y);
    }
    kd.work();
    return 0;
}
/*
3 4
1 2 3
1 2
2 3
2 1
3 4
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值