CDQ分治(三维偏序集)

排序,三关键字

去重

归并排序+树状数组

#include<bits/stdc++.h>
using namespace std;
#define re register int
const int N=100010;
const int M=200010;
int n,m;
struct node{
    int a,b,c,s,res;
    bool operator < (node y) const {
        if(a==y.a&&b==y.b)return c<y.c;
        if(a==y.a)return b<y.b;
        return a<y.a;
    }
    bool operator == (node y) const {
        return a==y.a&&b==y.b&&c==y.c;
    }
}q[N],w[N];int cnt;
int tr[M+100],ans[N];
void ins(int x,int v){
    for(re i=x;i<M;i+=(i&(-i)))tr[i]+=v;
}
int query(int x){
    int ret=0;
    for(re i=x;i;i-=(i&(-i)))ret+=tr[i];
    return ret;
}
void merge_sort(int l,int r){
    if(l>=r)return ;
    int mid=l+r>>1;
    merge_sort(l,mid);
    merge_sort(mid+1,r);
    int i=l,j=mid+1,k=l;
    while(i<=mid&&j<=r){
        if(q[i].b<=q[j].b)ins(q[i].c,q[i].s),w[k++]=q[i++];
        else q[j].res+=query(q[j].c),w[k++]=q[j++];
    }
    while(i<=mid)ins(q[i].c,q[i].s),w[k++]=q[i++];
    while(j<=r)q[j].res+=query(q[j].c),w[k++]=q[j++];
    for(i=l;i<=mid;i++)ins(q[i].c,-q[i].s);
    //for(i=1;i<=M;i++)if(tr[i]==0)cout<<tr[i]<<endl;
    for(i=l;i<=r;i++)q[i]=w[i];
}
signed main(){
    scanf("%d%d",&n,&m);
    for(re i=1;i<=n;i++){
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        q[i]={a,b,c,1};
    }
    sort(q+1,q+n+1);
    for(re i=1;i<=n;i++){
        //cout<<q[i].a<<" "<<q[i].b<<" "<<q[i].c<<" "<<q[i].s<<endl;
        if(q[i]==q[i-1])q[cnt].s++;
        else q[++cnt]=q[i];
    }
    /*for(re i=1;i<=cnt;i++){
        cout<<q[i].a<<" "<<q[i].b<<" "<<q[i].c<<" "<<q[i].s<<endl;
    }*/
    merge_sort(1,cnt);
    for(re i=1;i<=cnt;i++){
        //cout<<q[i].a<<" "<<q[i].b<<" "<<q[i].c<<" "<<q[i].s<<" "<<q[i].res<<endl;
        ans[q[i].res+q[i].s-1]+=q[i].s;
    }
    for(re i=0;i<n;i++)printf("%d\n",ans[i]);
}

 关于为什么按照单关键字排序是错误的?

我们很容易认为,a被sort排好了,b被归并排好了,c在树状数组里统计好了

可是你忘记了一点,在向线段树中插入c的时候,我们要确保插入的每一个c所属的节点的a和b都在现在的a,b之前

所以我们必须要按照三关键字排序。。。。

 

当然这玩意在有些情况下是不成立的(也就是说,在不需要去重的情况下)

我们可以只对某一个关键字进行排序,或者这个关键字是天然排好的-----天使玩偶

所以在某些情况下,我们可以对CDQ分治的算法进行优化,省掉一个nlogn的时间,也就会快很多

 

还有一个问题,在利用CDQ做题的时候,最好不要设置重复元素,不然会WA的很惨

 

佳媛姐姐

这个题又为我们提供了关于CDQ分治的做法,就是我们可以去改变归并排序的顺序

就是前序,中序,后序合并,来满足题目的要求

就这道题,如果要是后序的话,我们无论如何都不能把所有情况找全,所以我们就进行中序归并

这样每次都会造成乱序,我们在时间复杂度允许的情况下使用“sort”,如果不行就用“归并”;

这样这道题就愉快的通过了

#include<bits/stdc++.h>
using namespace std;
#define re register int
const int N=100005;
struct node{
    int a,maxn,minn,bl;
}q[N];
bool comp0(node x,node y){return x.bl<y.bl;}
bool comp1(node x,node y){return x.maxn<y.maxn;}
bool comp2(node x,node y){return x.a<y.a;}
int n,m;
int tr[N],ans[N];
void add(int x,int v){
    for(re i=x;i<=n;i+=(i&(-i)))tr[i]=max(tr[i],v);
}
int query(int x){
    int ret=0;
    for(re i=x;i;i-=(i&(-i)))ret=max(ret,tr[i]);
    return ret;
}
void clear(int x){
    for(re i=x;i<=n;i+=(i&(-i))){
        if(tr[i]==0)break;
        tr[i]=0;
    }
}
void merge_sort(int l,int r){
    if(l>=r){
        ans[q[l].bl]=max(ans[q[l].bl],1);
        return ;
    }
    int mid=l+r>>1;
    merge_sort(l,mid);
    sort(q+l,q+mid+1,comp1);
    sort(q+mid+1,q+r+1,comp2);
    //cout<<l<<" "<<mid<<" "<<r<<" "<<q[l].a<<" "<<q[r].a<<endl;
    int i=l,j=mid+1;
    while(i<=mid&&j<=r){
        if(q[i].maxn<=q[j].a)add(q[i].a,ans[q[i].bl]),i++;
        else ans[q[j].bl]=max(ans[q[j].bl],query(q[j].minn)+1),j++;
    }
    while(i<=mid)add(q[i].a,ans[q[i].bl]),i++;
    while(j<=r)ans[q[j].bl]=max(ans[q[j].bl],query(q[j].minn)+1),j++;
    //cout<<query(q[j-1].minn)<<" "<<q[j-1].minn<<" "<<q[i-1].a<<" "<<ans[q[j-1].bl]<<endl;
    for(i=l;i<=mid;i++)clear(q[i].a);
    sort(q+l,q+r+1,comp0);
    merge_sort(mid+1,r);
}
signed main(){
    scanf("%d%d",&n,&m);
    for(re i=1;i<=n;i++){
        int x;scanf("%d",&x);
        q[i].a=x;q[i].maxn=x;q[i].minn=x;q[i].bl=i;
    }
    for(re i=1;i<=m;i++){
        int x,y;scanf("%d%d",&x,&y);
        q[x].maxn=max(q[x].maxn,y);
        q[x].minn=min(q[x].minn,y);
    }
    //for(re i=1;i<=n;i++)cout<<i<<" "<<q[i].a<<" "<<q[i].maxn<<" "<<q[i].minn<<endl;
    merge_sort(1,n);
    int sum=0;
    for(re i=1;i<=n;i++)sum=max(sum,ans[i]);
    printf("%d",sum);
}
View Code

 

posted @ 2021-06-12 15:33  fengwu2005  阅读(62)  评论(0编辑  收藏  举报