BZOJ2253 2010 Beijing wc 纸箱堆叠 CDQ分治

这题之前度娘上没有CDQ分治做法,gerwYY出来以后写了一个。不过要sort3遍,常数很大。

gerw说可以类似划分树的思想优化复杂度,但是蒟蒻目前不会划分树(会了主席树就懒得去弄了)。

嗯 将memset改成手动clear会快很多。

还有就是第一维相同的情况,划分为两个不存在第一维相同的两个区间即可。

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
const int Maxn=100000 + 10;
int C[Maxn*2],ans=0,A,P,n=0,h[Maxn],tot=0;
struct Node{
    int a,b,c,ans;
    void init(int x,int y,int z){
        if(x>y)swap(x,y);
        if(x>z)swap(x,z);
        if(y>z)swap(y,z);
        a=x,b=y,h[++tot]=c=z;
        ans=1;
    }
}p[Maxn],q[Maxn];
inline void Add(int x,const int&y){
    for(;0<x&&x<=n;x+=x&-x)C[x]=max(C[x],y);
}
inline void HashIt(int&x){
    x=lower_bound(h+1,h+n+1,x)-h;
}
inline int Query(int x){
    int ret=0;
    for(;0<x&&x<=n;x-=x&-x)ret=max(ret,C[x]);
    return ret;
}
inline void Clear(int x) {
    for(;x<=n;x+=x&-x)C[x]=0;
}
inline bool cmpa(const Node&x,const Node&y){
    if(x.a!=y.a)return x.a<y.a;
    if(x.b!=y.b)return x.b<y.b;
    return x.c<y.c;
}
inline bool cmpb(const Node&x,const Node&y){
    if(x.b!=y.b)return x.b<y.b;
    return x.c<y.c;
}
void init(){
    scanf("%d%d%d",&A,&P,&n);
    for(int a,b,c,t=1,i=1;i<=n;i++){
        a=(t=(long long)A*t%P);
        b=(t=(long long)A*t%P);
        c=(t=(long long)A*t%P);
        p[i].init(a,b,c);
    }
    sort(p+1,p+n+1,cmpa);
    sort(h+1,h+n+1);
    for(int i=1;i<=n;i++)HashIt(p[i].c);
}

void CDQ(int l,int r){
    if(l==r)return;
    int mid=-1,L=(l+r)>>1,R=L+1;
    while(l<=L || R<=r){
        if(l<=L && p[L].a!=p[L+1].a){mid=L;break;}
        if(R<=r && p[R].a!=p[R-1].a){mid=R-1;break;}
        L--,R++;
    }
    if(mid==-1)return;
    CDQ(l,mid);
    sort(p+l,p+mid+1,cmpb);
    sort(p+mid+1,p+r+1,cmpb);
    int i=l;
    for(int j=mid+1;j<=r;j++){
        for(;i<=mid && p[i].b<p[j].b;i++)Add(p[i].c,p[i].ans);
        p[j].ans=max(p[j].ans,Query(p[j].c-1)+1);
    }
    for(int j=l;j<=i;j++)Clear(p[j].c);
    sort(p+mid+1,p+r+1,cmpa);
    CDQ(mid+1,r);
}
int main(){
    init();
    CDQ(1,n);
    for(int i=1;i<=n;i++)
        if(p[i].ans>ans)ans=p[i].ans;
    printf("%d
",ans);
    return 0;
}
原文出处http://www.cnblogs.com/showson/
原文地址:https://www.cnblogs.com/showson/p/4277807.html