1. 程式人生 > >[CQOI 2011]動態逆序對

[CQOI 2011]動態逆序對

int 支持 ret -m 樹套樹 match 一個數 排序 wap

Description

題庫鏈接

對於序列 \(A\) ,它的逆序對數定義為滿足 \(i<j\) ,且 \(A_i>A_j\) 的數對 \((i,j)\) 的個數。給 \(1\)\(n\) 的一個排列,按照某種順序依次刪除 \(m\) 個元素,你的任務是在每次刪除一個元素之前統計整個序列的逆序對數。

Solution

好久以前的坑了...

解法一

考慮樹套樹。

刪去一個數,減少的逆序對個數是當前位置之前比當前數大的個數以及在這個數的位置之後比當前數小的個數。

如果不支持修改顯然是可以用主席樹來維護的。

由於要支持修改,我們考慮用樹狀數組套線段樹,樹狀數組維護序列下標。線段樹維護數的個數。那麽時間和空間復雜度都是 \(O(n\cdot 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('\n')) #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('\n'))
#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;
}

[CQOI 2011]動態逆序對