• [CQOI 2011]动态逆序对


    Description

    题库链接

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

    Solution

    好久以前的坑了...

    解法一

    考虑树套树。

    删去一个数,减少的逆序对个数是当前位置之前比当前数大的个数以及在这个数的位置之后比当前数小的个数。

    如果不支持修改显然是可以用主席树来维护的。

    由于要支持修改,我们考虑用树状数组套线段树,树状数组维护序列下标。线段树维护数的个数。那么时间和空间复杂度都是 (O(ncdot log^2_2 n)) 的。

    解法二

    考虑 (cdq)

    首先删数很不好操作,我们考虑从后往前操作,让删数变成添数。

    我们可以先按时间排序。添加时间早的数才会对添加时间晚的有贡献。对于 (cdq) 的每一次操作就是统计添数时间早于某个数的当前位置之前比当前数大的个数以及在这个数的位置之后比当前数小的个数。

    Code

    解法一

    //It is made by Awson on 2018.2.24
    #include <bits/stdc++.h>
    #define LL long long
    #define dob complex<double>
    #define Abs(a) ((a) < 0 ? (-(a)) : (a))
    #define Max(a, b) ((a) > (b) ? (a) : (b))
    #define Min(a, b) ((a) < (b) ? (a) : (b))
    #define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
    #define writeln(x) (write(x), putchar('
    '))
    #define lowbit(x) ((x)&(-(x)))
    using namespace std;
    const int N = 100000;
    void read(int &x) {
        char ch; bool flag = 0;
        for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || 1); ch = getchar());
        for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar());
        x *= 1-2*flag;
    }
    void print(LL x) {if (x > 9) print(x/10); putchar(x%10+48); }
    void write(LL x) {if (x < 0) putchar('-'); print(Abs(x)); }
    
    int n, m, a, id[N+5]; LL ans;
    struct Segment_tree {
        int root[N+5], ch[N*100][2], key[N*100+5], pos;
        int cpynode(int x) {++pos; ch[pos][0] = ch[x][0], ch[pos][1] = ch[x][1], key[pos] = key[x]; return pos; }
        void insert(int &o, int l, int r, int loc, int val) {
        if (o == 0) o = cpynode(o); key[o] += val;
        if (l == r) return; int mid = (l+r)>>1;
        if (loc <= mid) insert(ch[o][0], l, mid, loc, val); else insert(ch[o][1], mid+1, r, loc, val);
        }
        int query(int o, int l, int r, int a, int b) {
        if ((a <= l && r <= b) || o == 0) return key[o];
        int mid = (l+r)>>1;
        int c1 = 0, c2 = 0;
        if (a <= mid) c1 = query(ch[o][0], l, mid, a, b);
        if (b > mid) c2 = query(ch[o][1], mid+1, r, a, b);
        return c1+c2;
        }
    }ST;
    struct bittree {
        void add(int o, int val, int key) {for (; o <= n; o += lowbit(o)) ST.insert(ST.root[o], 1, n, val, key); }
        int query(int o, int l, int r) {
        int ans = 0;
        for (; o; o -= lowbit(o)) ans += ST.query(ST.root[o], 1, n, l, r);
        return ans;
        }
    }BT;
    
    void work() {
        read(n); read(m);
        for (int i = 1; i <= n; i++) read(a), BT.add(i, a, 1), ans += BT.query(i-1, a, n), id[a] = i;
        for (int i = 1; i <= m; i++) {
        writeln(ans); read(a);
        ans -= BT.query(id[a]-1, a, n);
        ans -= BT.query(n, 1, a);
        ans += BT.query(id[a], 1, a);
        BT.add(id[a], a, -1);
        }
    }
    int main() {
        work(); return 0;
    }

    解法二

    //It is made by Awson on 2018.2.25
    #include <bits/stdc++.h>
    #define LL long long
    #define dob complex<double>
    #define Abs(a) ((a) < 0 ? (-(a)) : (a))
    #define Max(a, b) ((a) > (b) ? (a) : (b))
    #define Min(a, b) ((a) < (b) ? (a) : (b))
    #define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
    #define writeln(x) (write(x), putchar('
    '))
    #define lowbit(x) ((x)&(-(x)))
    using namespace std;
    const int N = 1e5;
    void read(int &x) {
        char ch; bool flag = 0;
        for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || 1); ch = getchar());
        for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar());
        x *= 1-2*flag;
    }
    void print(LL x) {if (x > 9) print(x/10); putchar(x%10+48); }
    void write(LL x) {if (x < 0) putchar('-'); print(Abs(x)); }
    
    int n, m, match[N+5], d; LL ans[N+5];
    struct tt {int x, y, t, flag; }a[N+5], b[N+5];
    struct bittree {
        int c[N+5];
        void add(int o, int val) {for (; o <= n; o += lowbit(o)) c[o] += val; }
        int query(int o) {int ans = 0; for (; o; o -= lowbit(o)) ans += c[o]; return ans; }
    }T;
    bool comp1(const tt &a, const tt &b) {return a.t < b.t; }
    bool comp2(const tt &a, const tt &b) {return a.x < b.x; }
    
    void CDQ(int l, int r) {
        if (l == r) return; int mid = (l+r)>>1;
        for (int i = l; i <= mid; i++) b[i] = a[i], b[i].flag = 1;
        for (int i = mid+1; i <= r; i++) b[i] = a[i], b[i].flag = 0;
        sort(b+l, b+r+1, comp2);
        for (int i = l; i <= r; i++) if (b[i].flag == 1) T.add(b[i].y, 1); else ans[b[i].t] += T.query(n)-T.query(b[i].y);
        for (int i = l; i <= r; i++) if (b[i].flag == 1) T.add(b[i].y, -1);
        for (int i = r; i >= l; i--) if (b[i].flag == 1) T.add(b[i].y, 1); else ans[b[i].t] += T.query(b[i].y);
        for (int i = l; i <= r; i++) if (b[i].flag == 1) T.add(b[i].y, -1);
        CDQ(l, mid), CDQ(mid+1, r);
    }
    void work() {
        read(n), read(m); for (int i = 1; i <= n; i++) read(a[i].y), a[i].x = i, match[a[i].y] = i; int times = n;
        for (int i = 1; i <= m; i++) read(d), a[match[d]].t = times--;
        for (int i = 1; i <= n; i++) if (a[i].t == 0) a[i].t = times--;
        sort(a+1, a+n+1, comp1); CDQ(1, n);
        LL Ans = 0; for (int i = 1; i <= n; i++) Ans += ans[i];
        for (int i = n; i > n-m; i--) writeln(Ans), Ans -= ans[i];
    }
    int main() {
        work(); return 0;
    }
  • 相关阅读:
    大整数乘除法
    java大神进阶之路
    自定义Swap
    指针基础详解
    已知前序中序求后序(转载)
    杭电1003_Max Sum
    回溯法求解迷宫问题
    linux下安装QQ等EXE文件
    java工程中使用freemarker例子
    maven自动部署到tomcat的问题
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/8470575.html
Copyright © 2020-2023  润新知