• cdq分治入门学习 cogs 1752 Mokia nwerc 2015-2016 G 二维偏序


    
    /*
    
    CDQ分治的对象是时间。
    即对于一个时间段[L, R],我们取mid = (L + R) / 2。
    分治的每层只考虑mid之前的修改对mid之后的查询的贡献,然后递归到[L,mid],(mid,R]。
    显然,CDQ分治是一种离线算法,我们需要将所有的修改/查询存下来,一起进行操作。
    同时,CDQ分治还需要满足:操作之间相互独立,即一个操作的存在不会影响到另一个操作的存在。
    经典入门题  单点修改 矩形查询
    如果此题矩形小一点的话 可以使用树状数组套线段树
    但是矩形过大时就不适用了
    这里可以将一个询问拆成四个前缀和查询,然后和修改操作一起 做cdq分治
    */
    #include<bits/stdc++.h>
    #define LL long long
    
    using namespace std;
    const int N = 2e6 + 1;
    
    int tr[N],W;
    int lowbit(int x){return x & (-x);}
    void up(int pos,int v){
        for(;pos <= W;pos += lowbit(pos)) tr[pos] += v;
    }
    int getsum(int pos){
        int ans = 0;
        for(;pos;pos -= lowbit(pos)) ans += tr[pos];
        return ans;
    }
    struct Q{
        int x, y, type, q, v, order;
        Q(){};
        Q(int x,int y,int type, int q,int v,int order):x(x),y(y),type(type),q(q),v(v),order(order){};
        bool operator<(const Q&rhs)const{
            return x < rhs.x;
        }
    }qr[N],tmp[N];
    int ans[N];
    void cdq(int l,int r){
        if(l == r) return ;
        int mid = l + r >> 1;
        int p1 = l,p2 = mid + 1;
        /// 首先将mid之前的操作 全部放到mid左边 mid之后的操作全部放到右边,保证了按时间分治,并且左右都是x递增的
        for(int i = l;i <= r;i++){
            if(qr[i].order <= mid) tmp[p1++] = qr[i];
            else tmp[p2++] = qr[i];
        }
        for(int i = l;i <= r;i++) qr[i] = tmp[i];
        int j = l;
        ///计算完mid时间轴左边的修改对右边查询的贡献,恢复修改
        for(int i = mid + 1;i <= r;i++){
             if(qr[i].type == 2) {
                for(; j <= mid && qr[j].x <= qr[i].x; j++){
                    if(qr[j].type == 1) up(qr[j].y,qr[j].v);
                }
                ans[qr[i].q] += qr[i].v * getsum(qr[i].y);
             }
        }
        for(int i = l;i < j;i++) if(qr[i].type == 1) up(qr[i].y, -qr[i].v);
        ///进行递归分治
        cdq(l, mid);cdq(mid + 1, r);
    }
    int main()
    {
    
        int op, a, b, c, d, id = 0, tot = 0;
        while(scanf("%d", &op) && op != 3){
            if(op == 0)
                scanf("%d", &W);
            else if(op == 1){
                scanf("%d%d%d", &a, &b, &c);
                qr[++id] = Q(a, b, 1, 0, c, id);
            }
            else{
                ++tot;
                scanf("%d%d%d%d", &a, &b, &c, &d);
                qr[++id] = Q(a - 1, b - 1, 2, tot, 1, id);
                qr[++id] = Q(c, d, 2, tot, 1, id);
                qr[++id] = Q(a - 1, d, 2, tot, -1, id);
                qr[++id] = Q(c, b - 1, 2, tot, -1, id);
            }
        }
        sort(qr + 1, qr + id + 1);
        cdq(1, id);
        for(int i = 1; i <= tot; i++)
            printf("%d
    ", ans[i]);
        return 0;
    }
    
    
    
    
    
    
    http://codeforces.com/gym/101485/attachments
    求出多少对(i,j) 满足i < j 且a[j] < a[i] 且 b[j] < b[i]
    做法 第一维分治 第二维树状数组 时间复杂度为O(nlognlogn) 空间复杂度O(n)
    解决二维偏序问题 其他做法可能空间复杂度为过高
    
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<set>
    #include<queue>
    #define LL long long
    using namespace std;
    #define ms(dp,x) memset(dp,x,sizeof dp)
    
    const int N = 2e5 + 10;
    LL ans;
    int n;
    int tr[N];
    int vis[N];
    struct Q{
        int id,a,b,c;
        Q(){};
    }q[N];
    
    int lowbit(int x){return x &(-x);}
    void up(int pos,int v){
        for(;pos <= n;pos += lowbit(pos)) tr[pos] += v;
    }
    int getsum(int pos){
        int ans = 0;
        for(;pos;pos -= lowbit(pos)) ans += tr[pos];
        return ans;
    }
    bool cmpx(Q x,Q y){return x.b < y.b;}
    bool cmprx(Q x,Q y){return x.id < y.id;}
    void cdq(int l,int r){
        if(l == r) return ;
        int mid = l + r >> 1;
        cdq(l,mid);
        sort(q + l,q + mid + 1, cmpx);
        sort(q + mid + 1,q + r + 1, cmpx);
        int i = l;
        LL tmp = 0;
        for(int j = mid + 1;j <= r;j++){
            while(i <= mid && q[i].b < q[j].b) {
                up(q[i++].c,1);
            }
            tmp += getsum(q[j].c - 1);
        }
        ans += tmp;
        i = l;
        for(int j = mid + 1;j <= r;j++){
            while(i <= mid && q[i].b < q[j].b) {
                up(q[i++].c,-1);
            }
        }
        sort(q + mid + 1,q + r + 1, cmprx);
        cdq(mid + 1,r);
    }
    int main()
    {
       int x;
       while(scanf("%d",&n)==1){
    
         for(int i = 1;i <= n;i++) {
            scanf("%d",&q[i].a);
            vis[q[i].a] = i;
            q[i].id = i;
         }
         for(int i = 1;i <= n;i++) {
            scanf("%d",&x);
            q[vis[x]].b = i;
         }
         for(int i = 1;i <= n;i++) {
            scanf("%d",&x);
            q[vis[x]].c = i;
         }
         memset(tr, 0, sizeof tr);
         ans = 0;
         cdq(1,n);
         printf("%lld
    ",ans);
       }
        return 0;
    }
    /*
    8
    1 4 8 3 5 7 2 6
    6 4 8 3 5 2 7 1
    6 4 8 3 5 2 7 1
    */
    
  • 相关阅读:
    Gartner:当商业智能成熟度低时,如何加快分析采用率
    年薪50万的大数据分析师养成记
    数据化管理在餐饮业中的应用
    linux下查看本机socket端口详细信息
    nginx模块编程之获取客户ip及端口号
    大小端模式转换函数
    Nginx代码调试——gdb工具
    Nginx入门之两种handler函数的挂载方式
    Nginx重要结构request_t解析之http请求的获取
    Nginx_handler模块发开(hello模块结构解析)
  • 原文地址:https://www.cnblogs.com/jiachinzhao/p/7719131.html
Copyright © 2020-2023  润新知