zoukankan      html  css  js  c++  java
  • BZOJ3295: [Cqoi2011]动态逆序对(cdq分治)

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 6912  Solved: 2438
    [Submit][Status][Discuss]

    Description

    对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数。给1到n的一个排列,按照某种顺序依次删
    除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数

    Input

    输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数。
    以下n行每行包含一个1到n之间的正整数,即初始排列。
    以下m行每行一个正整数,依次为每次删除的元素。
    N<=100000 M<=50000

    Output

     
    输出包含m行,依次为删除每个元素之前,逆序对的个数。

    Sample Input

    5 4
    1
    5
    3
    4
    2
    5
    1
    4
    2

    Sample Output

    5
    2
    2
    1
    样例解释
    (1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。

    HINT

    Source

    这题已知有三种做法:

    1、主席树+树状数组

    2、树套树随便套

    3、cdq分治

    用cdq分治的话有一种非常巧妙的思路:先时间倒流,那么每次询问就转化成了求逆序对的个数

    其实也不用。。

    我们考虑一个数删除之后会对答案产生怎样的贡献

    设当前删除了第$i$个元素,那么在$1 - i$中比它大的都要减去

    在$(i + 1) - N$中比他小的都要减去

    这样的话直接正着循环一遍再倒着循环一遍就行了。

    用树状数组求逆序对

    代码借鉴的candy大佬,写的非常妙

    #include<cstdio>
    #include<vector>
    #include<algorithm>
    #define LL long long 
    using namespace std;
    const int MAXN = 400001, INF = 1e9 + 10;
    inline int read() {
        char c = getchar(); int x = 0, f = 1;
        while(c < '0' || c > '9'){if(c == '-')f = -1; c = getchar();}
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * f;
    }
    struct Query {
        int t, x, val, type, id;
        bool operator < (const Query &rhs) const {
            return x == rhs.x ? val < rhs.val : x < rhs.x;
        }
    }Q[MAXN], Tp[MAXN];
    int N, M, a[MAXN], pos[MAXN], tim;
    LL ans[MAXN];
    
    #define lb(x) (x & -x)
    int T[MAXN];
    void Add(int pos, int val) {for(int i = pos; i <= N; i += lb(i)) T[i] += val;}
    int Sum(int pos) {int ans = 0; for(int i = pos; i >= 1; i -= lb(i)) ans += T[i]; return ans;}
    
    void CDQ(int l, int r) {
        if(l == r) return;
        int mid = l + r >> 1;
        for(int i = l; i <= r; i++) 
            if(Q[i].t <= mid) Add(Q[i].val, Q[i].type);
            else ans[Q[i].id] += Q[i].type * (Sum(N) - Sum(Q[i].val));
        for(int i = l; i <= r; i++) if(Q[i].t <= mid) Add(Q[i].val, -Q[i].type);
        
        for(int i = r; i >= l; i--) 
            if(Q[i].t <= mid) Add(Q[i].val, Q[i].type);
            else ans[Q[i].id] += Q[i].type * (Sum(Q[i].val - 1));
        for(int i = l; i <= r; i++)if(Q[i].t <= mid) Add(Q[i].val, -Q[i].type);
        
        int p1 = l, p2 = mid + 1;
        for(int i = l; i <= r; i++)
            if(Q[i].t <= mid) Tp[p1++] = Q[i];
            else Tp[p2++] = Q[i];
        for(int i = l; i <= r; i++) Q[i] = Tp[i];
        CDQ(l, mid); CDQ(mid + 1, r);
    }
    int main() {
    #ifdef WIN32
        //freopen("a.in", "r", stdin);
    #endif
        N = read(); M = read();
        for(int i = 1; i <= N; i++) {
            a[i] = read(); pos[a[i]] = i ;
            Q[++tim] = (Query) {tim, i, a[i], 1, 0};
        }
        for(int i = 1; i <= M; i++) {
            int x = read();
            Q[++tim] = (Query) {tim, pos[x], x, -1, i};
        }
        sort(Q + 1, Q + tim + 1);
        CDQ(1, tim);
        for(int i = 1; i <= M; i++) {
            ans[i] += ans[i - 1];
            printf("%lld
    ", ans[i - 1]);
        }
        return 0;
    }
  • 相关阅读:
    Mongodb 的ORM框架 Morphia之注解
    Redis主从集群及哨兵模式
    Dubbo
    Zookeeper
    使用Dockerfile自定义一个包含centos,tomcat的镜像
    linux/centOS 下安装 ngnix
    Session共享
    Linux安装jdk.18和tomcat8
    MongoDB集群的搭建
    多态--方法重写的三个要点
  • 原文地址:https://www.cnblogs.com/zwfymqz/p/9299692.html
Copyright © 2011-2022 走看看