【BZOJ2253】[2010 Beijing wc]纸箱堆叠 CDQ分治

简单来说,题中要求三维 LIS.

考虑如何使用 CDQ 分治.

我们可以事先将坐标按 $x$ 轴排序,先递归处理左边,再考虑左边对右边的影响.

由于我们再处理该段区间之前已经将该区间按照 $x$ 坐标排序,我们便能保证右区间的 $x$ 坐标一定不小于左区间的 $x$ 坐标.

这样有什么好处呢 ? 

这不就可以将一个 3 维的问题转成 2 维的问题了吗 ? 

由于我们只需考虑左区间对右区间的影响,我们无需考虑 $x$ 坐标所带来的困扰.

想象一下二维问题怎么做 ? 

对右区间和左区间分别按照 $y$ 坐标为第一关键字, $z$ 坐标按照第二关键字排序,利用双指针分别扫描左右区间.

设两个指针分别为 $tl$ 和 $tr$. 

我们分这两种情况来讨论.

1. $arr[tl].y<=arr[tr].y$

这时由于左面的比右面小,说明左面的还可能出现比右面小的情况,就不急着查询,而且左面该点还会对右面产生影响.

所以,我们利用左面的更新右面,并 $++tl$.

2. $arr[tl].y>arr[tr].y$

左面的大于右面的,则右面该点在以后也不可能再被左面所贡献,直接查询即可,并 $++tr$.

 

Code:

#include <cstdio>
#include <algorithm>
#include <cstring>
#define maxn 500060
#define ll long long 
#define nex (oo = (oo * A) % mod)
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
int n,cnt,fin,ans[maxn]; 
long long mod,oo = 1,A,H[maxn]; 
void getmax(int &a,int b){ if(b>a) a = b; }
struct Node{
    long long  x,y,z; 
    int id; 
}node[maxn],arr[maxn]; 

int cmpx(Node a,Node b){ return(a.x==b.x&&a.y==b.y)? (a.z < b.z) : ((a.x==b.x)?a.y<b.y:a.x<b.x); }
int cmpy(Node a,Node b) {
    if(a.y==b.y)  return a.z<b.z;  
    return a.y<b.y; 
}
int equal(Node a,Node b) { return (a.x==b.x&&a.y==b.y&&a.z==b.z); }

struct BIT{
    int C[maxn];
    int lowbit(int x){ return x & (-x); }
    void update(int p,int x) { 
        while(p <  maxn) {
            C[p] = max(C[p],x);
            p += lowbit(p);
        } 
    }
    int query(int p) { 
        if(p<=0) return 0; 
        int ss=0;
        while(p>0) {
            ss=max(ss,C[p]),p-=lowbit(p); 
        }
        return ss; 
    }
    void del(int p) { 
        while(p < maxn) C[p] = 0,p+=lowbit(p); 
    }
}tree;
void solve(int l,int r){
    if(l >= r) return;
    int mid = (l + r) >> 1,tl = l,tr = mid+1; 
    solve(l,mid); 
    sort(arr + l,arr + mid + 1,cmpy),sort(arr + mid + 1,arr + r + 1,cmpy);  
    while(tl<=mid&&tr<=r) {
        if(arr[tl].y<arr[tr].y) {
            tree.update(arr[tl].z,ans[arr[tl].id]);             
            ++tl;
        }
        else {
            getmax(ans[arr[tr].id],tree.query(arr[tr].z-1)+1); 
            ++tr; 
        }
    }
    for(int i = tr;i<=r;++i) getmax(ans[arr[i].id],tree.query(arr[i].z-1)+1); 
    for(int i = l;i<=mid;++i) tree.del(arr[i].z); 
    sort(arr+mid+1,arr+1+r,cmpx),solve(mid+1,r); 
}
int main(){
    //setIO("input");
    scanf("%lld%lld%d",&A,&mod,&n);             
    for(int i = 1;i <= n; ++i){
        oo = (oo * A) % mod,node[i].x = oo; 
        oo = (oo * A) % mod,node[i].y = oo;
        oo = (oo * A) % mod,node[i].z = oo;
        if(node[i].x > node[i].y) swap(node[i].x,node[i].y);
        if(node[i].x > node[i].z) swap(node[i].x,node[i].z);
        if(node[i].y > node[i].z) swap(node[i].y,node[i].z); 
    } 
    node[0].x = node[0].y = node[0].z = -333333333; 
    sort(node + 1,node + 1 + n,cmpx); 
    for(int i = 1;i <= n; ++i) 
        if(!equal(node[i],node[i-1])) arr[++cnt] = node[i],arr[cnt].id = cnt; 
    //================================================================================= 
    //对 x 离散
    for(int i = 1;i <= cnt; ++i) H[i] = arr[i].x;
    sort(H+1,H+1+cnt);
    for(int i = 1;i <= cnt; ++i) arr[i].x = lower_bound(H + 1,H + 1 + cnt,arr[i].x)-H;
    //对 y 离散
    for(int i = 1;i <= cnt; ++i) H[i] = arr[i].y;
    sort(H+1,H+1+cnt);
    for(int i = 1;i <= cnt; ++i) arr[i].y = lower_bound(H + 1,H + 1 + cnt,arr[i].y)-H;
    //对 z 离散
    for(int i = 1;i <= cnt; ++i) H[i] = arr[i].z;
    sort(H + 1,H + 1 + cnt);
    for(int i = 1;i <= cnt; ++i) arr[i].z = lower_bound(H + 1,H + 1 + cnt,arr[i].z)-H; 
    //=================================================================================

    for(int i = 1;i <= cnt; ++i) ans[arr[i].id] = 1; 
    solve(1,cnt);

    for(int i = 1;i <= cnt; ++i) fin = max(fin,ans[arr[i].id]);
    printf("%d",fin); 
    return 0; 
}

  

posted @ 2019-02-12 10:38  EM-LGH  阅读(166)  评论(0编辑  收藏  举报