四维偏序的一个单根复杂度,空间线性的做法

一个单根复杂度,空间线性的做法,以下默认块长为 n\sqrt{n}n

考虑对点按 aaa 为第一关键字排序后分块,对于每个块单独考虑。

思路即是每次考虑到了一个块,就把前缀块按 bbb 为第一关键字排序,把当前块也按 bbb 为第一关键字排序。然后扫描线,一个个考虑当前块的元素,将前缀块中 $b\leq $ 当前元素 bbbcccddd 塞进二维值域分块中,再对当前块的点查询 ccc 比他小的且 ddd 比他小的数的 dpdpdp 的最大值即可。

发现一个惊人的事实,前缀块的 cccddd 中可以对当前块的 cccddd 相对大小关系离散化,这样值域范围就是单根,二维值域分块即是插入 O(1)O(1)O(1) ,查询 O(n4⋅n4)=O(n)O(\sqrt[4]{n} \cdot \sqrt[4]{n})=O(\sqrt{n})O(4n4n)=O(n)。因为做了 n\sqrt{n}n 次扫描线,每次 nnn 次插入,复杂度 O(nn)O(n\sqrt{n})O(nn)。共有 nnn 次查询,每次 O(n)O(\sqrt{n})O(n) ,复杂度 O(nn)O(n\sqrt{n})O(nn)

对于块内的转移直接暴力即可,每个点至多从块中的 n\sqrt{n}n 个元素转移,复杂度为 O(nn)O(n\sqrt{n})O(nn)

对于离散化,先对于块内排序,复杂度为均摊整体为 O(nlog⁡2n)O(n\log_{2}{n})O(nlog2n) 。再对前缀块已经排好序的数列归并排序,只有 n\sqrt{n}n 次,单次 O(n)O(n)O(n) ,复杂度为 O(nn)O(n\sqrt{n})O(nn)

总结一下,我们得出了复杂度单根,空间 O(n)O(n)O(n) 的做法,我们因为发现前缀块的点能对当前块离散化而提出了此解法,可惜我自己实现的常数较大,如果有人有小常数解法,欢迎与我交流。

后来与其他人交流后发现有多种方法可以做到此复杂度,并且可能更好写或常数更小,但或许我这个方法也有自己的意义,就分享出来了。

#include <bits/stdc++.h>
using namespace std;
const int B=256,mb=16;
int mBid[B+10];
struct node{
    int fen[mb+2][mb+2],a[B+10][B+10],fen1[mb+2][B+10],fen2[B+10][mb+2];
    void Clear(){
        memset(fen,0,sizeof(fen));
        memset(a,0,sizeof(a));
        memset(fen1,0,sizeof(fen1));
        memset(fen2,0,sizeof(fen2));
    }
    void insert(int x,int y,int w){
        a[x][y]=max(a[x][y],w);
        fen1[mBid[x]][y]=max(fen1[mBid[x]][y],w);
        fen2[x][mBid[y]]=max(fen2[x][mBid[y]],w);
        fen[mBid[x]][mBid[y]]=max(fen[mBid[x]][mBid[y]],w);
    }
    int query(int x,int y){
        int Max=0;
        for(int i=x;i>=1;i--){
            if(mBid[i]!=mBid[x]){
                break;
            }
            for(int j=y;j>=1;j--){
                if(mBid[j]!=mBid[y]){
                    break;
                }
                Max=max(Max,a[i][j]);
            }
            for(int j=mBid[y]-1;j>=1;j--){
                Max=max(Max,fen2[i][j]);
            }
        }
        for(int j=y;j>=1;j--){
            if(mBid[j]!=mBid[y]){
                break;
            }
            for(int i=mBid[x]-1;i>=1;i--){
                Max=max(Max,fen1[i][j]);
            }
        }
        for(int i=mBid[x]-1;i>=1;i--){
            for(int j=mBid[y]-1;j>=1;j--){
                Max=max(Max,fen[i][j]);
            }
        }
        return Max;
    }
}Kuai;
struct nodee{
    int a,b,c,d,dp,W;
}A[50005],C[50005];
vector<int> lsha,lshb,lshc,lshd;
bool cmp(nodee aa,nodee bb){
    if(aa.a==bb.a){
        if(aa.b==bb.b){
            if(aa.c==bb.c){
                return aa.d<bb.d;
            }
            return aa.c<bb.c;
        }
        return aa.b<bb.b;
    }
    return aa.a<bb.a;
}
bool cmpp(nodee aa,nodee bb){
    if(aa.b==bb.b){
        if(aa.c==bb.c){
            if(aa.d==bb.d){
                return aa.a<bb.a;
            }
            return aa.d<bb.d;
        }
        return aa.c<bb.c;
    }
    return aa.b<bb.b;
}
int L[305],R[305],idB[50005],tot;
nodee num_yuan[50005],ti[50005],pai[50005],cun[50005];
bool cmpb(nodee aa,nodee bb){
    return aa.b<bb.b;
}
bool cmpc(nodee aa,nodee bb){
    return aa.c<bb.c;
}
bool cmpd(nodee aa,nodee bb){
    return aa.d<bb.d;
}
int Id_num_c[50005],Id_num_d[50005];
int n;
void chuli_c(int id){
    for(int i=1;i<=tot;i++){
        for(int j=pai[i-1].c+1;j<=pai[i].c;j++){
            Id_num_c[j]=i;
        }
    }
    for(int i=pai[tot].c+1;i<=n;i++){
        Id_num_c[i]=tot+1;
    }
}
void chuli_d(int id){
    for(int i=1;i<=tot;i++){
        for(int j=pai[i-1].d+1;j<=pai[i].d;j++){
            Id_num_d[j]=i;
        }
    }
    for(int i=pai[tot].d+1;i<=n;i++){
        Id_num_d[i]=tot+1;
    }
}
int main(){
    // ios::sync_with_stdio(0);
    // cin.tie(0);
    // cout.tie(0);
    cin>>n;
    for(int i=1;i<=B;i++){
        mBid[i]=(i-1)/mb+1;
    }
    for(int i=1;i<=n;i++){
        cin>>A[i].a>>A[i].b>>A[i].c>>A[i].d;
        lsha.push_back(A[i].a);
        lshb.push_back(A[i].b);
        lshc.push_back(A[i].c);
        lshd.push_back(A[i].d);
    }
    stable_sort(lsha.begin(),lsha.end());
    stable_sort(lshb.begin(),lshb.end());
    stable_sort(lshc.begin(),lshc.end());
    stable_sort(lshd.begin(),lshd.end());
    for(int i=1;i<=n;i++){
        A[i].a=lower_bound(lsha.begin(),lsha.end(),A[i].a)-lsha.begin()+1;
        A[i].b=lower_bound(lshb.begin(),lshb.end(),A[i].b)-lshb.begin()+1;
        A[i].c=lower_bound(lshc.begin(),lshc.end(),A[i].c)-lshc.begin()+1;
        A[i].d=lower_bound(lshd.begin(),lshd.end(),A[i].d)-lshd.begin()+1;
        A[i].W=1;
    }
    stable_sort(A+1,A+n+1,cmp);
    int N=0;
    for(int i=1;i<=n;i++){
        if(i==1 || A[i].a!=A[i-1].a || A[i].b!=A[i-1].b || A[i].c!=A[i-1].c || A[i].d!=A[i-1].d){
            C[++N]=A[i];
        }else{
            C[N].W++;
        }
    }
    for(int i=1;i<=N;i++){
        A[i]=C[i];
        A[i].dp=A[i].W;
    }
    n=N;
    int Cnt=0;
    for(int i=1;i<=n;i++){
        idB[i]=(i-1)/B+1;
        if(L[idB[i]]==0){
            L[idB[i]]=i;
        }
        R[idB[i]]=i;
        Cnt=(i-1)/B+1;
    }
    int Max=0;
    for(int i=1;i<=Cnt;i++){
        tot=0;
        for(int j=L[i];j<=R[i];j++){
            pai[++tot]=A[j];
            cun[tot]=A[j];
        }
        int cnt_c=0,cnt_d=0;
        stable_sort(pai+1,pai+tot+1,cmpc);
        chuli_c(i);
        int lst=0;
        for(int j=1;j<=tot;j++){
            cnt_c++;
            if(j==1 || pai[j].c!=lst){
                lst=pai[j].c;
                pai[j].c=cnt_c;
            }else{
                lst=pai[j].c;
                pai[j].c=pai[j-1].c;
            }
        }
        stable_sort(pai+1,pai+tot+1,cmpd);
        chuli_d(i);
        lst=0;
        for(int j=1;j<=tot;j++){
            cnt_d++;
            if(j==1 || pai[j].d!=lst){
                lst=pai[j].d;
                pai[j].d=cnt_d;
            }else{
                lst=pai[j].d;
                pai[j].d=pai[j-1].d;
            }
        }
        for(int j=1;j<L[i];j++){
            num_yuan[j].c=Id_num_c[num_yuan[j].c];
            num_yuan[j].d=Id_num_d[num_yuan[j].d];
            // cout<<num_yuan[j].a<<" "<<num_yuan[j].b<<' '<<num_yuan[j].c<<' '<<num_yuan[j].d<<' '<<num_yuan[j].dp<<'\n';
        }
        // cout<<"xiaofenge\n";
        stable_sort(pai+1,pai+tot+1,cmpp);
        stable_sort(cun+1,cun+tot+1,cmpp);
        int idl=1;
        Kuai.Clear();
        for(int j=1;j<=tot;j++){
            while(idl<L[i] && num_yuan[idl].b<=pai[j].b){
                Kuai.insert(num_yuan[idl].c,num_yuan[idl].d,num_yuan[idl].dp);
                idl++;
            }
            cun[j].dp=max(cun[j].dp,cun[j].W+Kuai.query(pai[j].c,pai[j].d));
            // cout<<cun[j].a<<' '<<pai[j].b<<' '<<pai[j].c<<' '<<pai[j].d<<' '<<pai[j].dp<<'\n';
        }
        for(int j=1;j<=tot;j++){
            for(int k=1;k<j;k++){
                if(cun[j].a>=cun[k].a && cun[j].b>=cun[k].b && cun[j].c>=cun[k].c && cun[j].d>=cun[k].d){
                    cun[j].dp=max(cun[j].dp,cun[k].dp+cun[j].W);
                }
            }
        }
        memcpy(num_yuan,ti,sizeof(num_yuan));
        merge(num_yuan+1,num_yuan+L[i],cun+1,cun+tot+1,ti+1,cmpp);
        memcpy(num_yuan,ti,sizeof(num_yuan));
        // cout<<"ZHONGFEN\n";
        // for(int j=1;j<=R[i];j++){
        //     cout<<num_yuan[j].a<<' '<<num_yuan[j].b<<' '<<num_yuan[j].c<<" "<<num_yuan[j].d<<' '<<num_yuan[j].dp<<'\n';
        // }
        // cout<<"Dafenge\n";
    }
    Max=0;
    for(int i=1;i<=n;i++){
        Max=max(Max,num_yuan[i].dp);
    }
    cout<<Max;
    return 0;
}
/*
13
10 5 9 9
12 10 1 13
13 13 6 1
3 7 1 5
9 8 7 8
6 9 4 11
8 1 11 6
5 3 1 10
7 2 12 11
10 5 8 3
2 11 5 2
4 4 12 4
1 11 10 7


*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值