• luogu3810 陌上花开 (cdq分治)


    求三维偏序

    设三维为a,b,c。先对a排序,这样i的偏序就只能<i。

    然而排序的时候需要三个维度都判断一遍,最后还要去重,不然会出现实际应该记答案的数出现在它后面的情况。

    (排序用的函数里不要写类似于<=之类的东西啊..会出奇奇怪怪的问题的(RE))

    然后分治来做,我们在做区间[l,r]的时候,先去做[l,m]和[m+1,r]

    之后左区间[l,m],右区间[m+1,r]都已经按照b排好序了,而且左右两区间内部的答案已经统计过了,所以现在只要考虑左区间中满足(右区间的数)的数量就好了。

    那么就也把[l,r]按照b排好序,在排的时候再用一个权值树状数组维护c,

    也就是,如果这个点是左区间的点,就把它的c值对应的树状数组中+=这个点的重复数(刚才去重了)

        如果这个点是右区间的点,就询问树状数组中<=它的c值的数量,然后加到这个点的答案里。

    而且每次做的时候树状数组都要清空,但不能用memset来清,复杂度有问题。(一直迷信memset的速度,结果一查告诉我也就比循环清快一倍??)

    所以只要把刚才加过的再减回去就可以了。

    复杂度$O(n*log_2n*log_2k)$

    也可以cdq套cdq,然后不用树状数组,复杂度是一样的。

    这样一直套下去,k维的话复杂度也就是$O(n*log^{k-1}_2n)$啦

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<cmath>
    #include<ctime>
    #define LL long long int
    #define inf 0x3f3f3f3f
    #define lowbit(x) ((x)&(-(x)))
    using namespace std;
    const int maxn=100010,maxk=200020;
    
    LL rd(){
       LL x=0;char c=getchar();int neg=1;
       while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();}
       while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
       return x*neg;
    }
    
    struct Node{
        int a,b,c,i;
    }inp[maxn],num[maxn],tmp[maxn];
    int iniN,N,K;
    int tr[maxk],cnt[maxn],siz[maxn],ans[maxn];
    
    inline bool cmp(Node a,Node b){return a.a==b.a?(a.b==b.b?a.c<b.c:a.b<b.b):a.a<b.a;}
    
    inline void add(int x,int y){
        while(x&&x<=K) tr[x]+=y,x+=lowbit(x);
    }
    inline int query(int x){
        int re=0;while(x) re+=tr[x],x-=lowbit(x);return re;
    }
    
    void cdq(int l,int r){
        int m=l+r>>1,p=l,q=m+1,t=0;
        if(l>=r) return;
        cdq(l,m);cdq(m+1,r);
        while(p<=m&&q<=r){
            if(num[p].b<=num[q].b){
                tmp[++t]=num[p];add(num[p].c,siz[num[p].i]);p++;
            }else{
                tmp[++t]=num[q];cnt[num[q].i]+=query(num[q].c);q++;
            }
        }    while(q<=r){
            tmp[++t]=num[q];cnt[num[q].i]+=query(num[q].c);q++;
        }for(int i=l;i<p;i++) add(num[i].c,-siz[num[i].i]);
        while(p<=m) tmp[++t]=num[p++];
    
        memcpy(num+l,tmp+1,sizeof(Node)*t);
    }
    
    int main(){
        int i,j,k;
        iniN=N=rd();K=rd();
        for(i=1;i<=N;i++){
            int a=rd(),b=rd(),c=rd();
            inp[i].a=a;inp[i].b=b;inp[i].c=c;num[i].i=i;
        }
        sort(inp+1,inp+N+1,cmp);//printf("ll");
        for(i=1,j=0;i<=N;i++){
            if(inp[i].a==inp[i-1].a&&inp[i].b==inp[i-1].b&&inp[i].c==inp[i-1].c) inp[i].i=j,cnt[j]++,siz[j]++;
            else{
                inp[i].i=++j;num[j]=inp[i];siz[j]=1;
            }
        }N=j;
        cdq(1,N);
        for(i=1;i<=N;i++) ans[cnt[i]]+=siz[i];
        for(i=0;i<iniN;i++) printf("%d
    ",ans[i]);
        return 0;
    }
  • 相关阅读:
    python字典推导式
    什么是Python 自省
    类变量和实例变量
    Python 使用正则表达式匹配URL网址
    python is 和 “==”的区别
    阮一峰老师的bash教程,建议阅读
    python里的闭包
    什么是生成器
    python访问限制
    pytorch使用Tips
  • 原文地址:https://www.cnblogs.com/Ressed/p/9533291.html
Copyright © 2020-2023  润新知