【BZOJ】2253: [2010 Beijing wc]纸箱堆叠

本文探讨了一种解决三维严格偏序最长链问题的方法,通过在第一维度排序后,利用二维平面上的前缀矩形最大值进行优化。采用加强剪枝的kdtree算法实现,展示了具体的代码实现细节。

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

题意

三维严格偏序最长链。(\(n \le 50000\)

分析

按第一维排序然后以第二和第三维作为关键字依次加入一个二维平面,维护前缀矩形最大值。

题解

当然可以树套树....可是似乎没有随机化算法快..
于是我们上加了强剪枝的kdtree....kdtree大法好...

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=50105;
struct node;
int A, P, Te=1, top;
struct ip {
    int p[3], d;
    node *ptr;
    void scan() {
        for(int i=0; i<3; ++i) {
            Te=(ll)A*Te%P;
            p[i]=Te;
        }
        sort(p, p+3);
        swap(p[0], p[1]);
        swap(p[1], p[2]);
        d=0; ptr=0;
    }
}a[N], *b[N];
struct node *null;
struct node {
    node *c[2], *f;
    int x[2], y[2], mx;
    ip *d;
    void up() {
        x[0]=min(d->p[0], min(c[0]->x[0], c[1]->x[0]));
        x[1]=max(d->p[0], max(c[0]->x[1], c[1]->x[1]));
        y[0]=min(d->p[1], min(c[0]->y[0], c[1]->y[0]));
        y[1]=max(d->p[1], max(c[0]->y[1], c[1]->y[1]));
    }
    void up2() {
        mx=max(d->d, max(c[0]->mx, c[1]->mx));
    }
    bool check(ip *a, int k) {
        return x[k]<a->p[0] && y[k]<a->p[1];
    }
    bool ok(ip *a) {
        return d->p[0]<a->p[0] && d->p[1]<a->p[1];
    }
    void init(ip *a) {
        c[0]=c[1]=null;
        x[0]=x[1]=a->p[0];
        y[0]=y[1]=a->p[1];
        mx=0;
        d=a;
    }
}Po[N], *iT=Po, *root, *st[N];
node *newnode(ip *a) {
    iT->init(a);
    return iT++;
}
int nowDep;
bool cmp(const ip *x, const ip *y) {
    return x->p[nowDep]==y->p[nowDep]?x->p[nowDep^1]<y->p[nowDep^1]:x->p[nowDep]<y->p[nowDep];
}
void build(int l, int r, node *&x, int dep) {
    if(l>r) {
        x=null;
        return;
    }
    nowDep=dep;
    int mid=(l+r)>>1;
    nth_element(b+l, b+mid, b+1+r, cmp);
    x=newnode(b[mid]);
    b[mid]->ptr=x;
    build(l, mid-1, x->c[0], dep^1); if(x->c[0]!=null) x->c[0]->f=x;
    build(mid+1, r, x->c[1], dep^1); if(x->c[1]!=null) x->c[1]->f=x;
    x->up();
}
int askMx;
void ask(ip *a, node *x) {
    if(x==null || !x->check(a, 0) || x->mx<=askMx) {
        return;
    }
    if(x->check(a, 1)) {
        askMx=max(askMx, x->mx);
    }
    if(x->ok(a)) askMx=max(askMx, x->d->d);
    ask(a, x->c[0]);
    ask(a, x->c[1]);
}
void update(node *x) {
    for(x->up2(); x!=root; x=x->f, x->up2());
}
int n;
int main() {
    null=iT++;
    null->x[0]=null->y[0]=~0u>>1;
    null->x[1]=null->y[1]=-(~0u>>1);
    null->d=0; null->mx=0;
    scanf("%d%d%d", &A, &P, &n);
    for(int i=1; i<=n; ++i) {
        a[i].scan();
        b[i]=&a[i];
    }
    build(1, n, root, 0);
    int ans=0;
    nowDep=2;
    sort(b+1, b+1+n, cmp);
    for(int i=1; i<=n; ++i) {
        askMx=0;
        ask(b[i], root);
        b[i]->d=askMx+1;
        st[++top]=b[i]->ptr;
        if(i!=n && b[i]->p[2]!=b[i+1]->p[2]) {
            while(top) update(st[top--]);
        }
        ans=max(ans, b[i]->d);
    }
    printf("%d\n", ans);
    return 0;
}

转载于:https://www.cnblogs.com/iwtwiioi/p/4985731.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值