P2448 無盡的生命

Description

小 a有一個長度無限長的序列 p = (1, 2, 3, 4 ……),初始時 pi = i
給出 m 個操做,每次交換兩個位置的數
詢問最後序列逆序對的個數node

Solution

忘了能夠樹狀數組直接作了.因此寫了很麻煩的線段樹.
大概寫一下怎麼作, 由於細節比較多.ios

咱們發現一次交換的其實是交換了兩個位置上的數.
咱們能夠將全部的位置分紅三類:數組

  • 有的位置會被改變(交換), 也對答案有貢獻;
  • 有的位置不會被改變, 也不會對答案有貢獻;
  • 有的位置不會被改變, 可是對答案有貢獻.ui

  • 第一類是全部的操做會交換的位置;
  • 第二類是被改變的第一個和最後一個位置往左和往右的數;
  • 第三類是不會被直接改變, 可是其左右都有被改變的數.spa

舉個例子:交換2和5位置, 數列變成\(1,5,3,4,2,6,7,\cdots\).
位置\(2, 5\)屬於第一類, 位置\(1,6,7,\cdots\)屬於第二類, 位置\(3, 4\)屬於第三類(由於與5位置造成逆序對)code

  • 對於不會被改變也沒有影響的數, 忽略存在就行了.
  • 對於不會被改變可是有影響的位置, 這些位置的行爲表現出來像是一個總體(會同時對另外一個位置產生或不產生逆序對).
    因此就把他們起來, 當作是一個特殊的數字就行了.

因此就將這些涉及到的位置離散化, 在離散化後按要求交換這些位置上的數造成一個數列,利用樹狀數組/線段樹求逆序對便可.ip

至於怎麼離散化, 看代碼就行了string

Code

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e6;
struct Node {
    long long val;
    Node *ls, *rs;
    Node(int _v = 0, Node *_ls = nullptr, Node *_rs = nullptr) :
        val(_v), ls(_ls), rs(_rs) { }
    void pushup() {
        val = ls->val + rs->val;
    }
    void mod(int k) { val += k; }
};
class Tree { // 普通的單調修改區間查詢線段樹
    int n;
    Node* root;
 #define LS l, mid, node->ls
 #define RS mid + 1, r, node->rs
    void build(int l, int r, Node* node) {
        if (l == r) return;
        int mid = l + r >> 1;
        node->ls = new Node();
        node->rs = new Node();
        build(LS), build(RS);
    }
    void insert(int l, int r, Node* node, int p, int k) {
        if (l == r) return node->mod(k);
        int mid = l + r >> 1;
        if (p <= mid) insert(LS, p, k);
        if (p >  mid) insert(RS, p, k);
        node->val = node->ls->val + node->rs->val;
    }
    long long query(int l, int r, Node* node, int L, int R) {
        if (l >= L and r <= R) 
            return node->val;
        int mid = l + r >> 1;
        long long res = 0;
        if (L <= mid) res += query(LS, L, R);
        if (R >  mid) res += query(RS, L, R);
        return res;
    }
  public:
    Tree(int _n) : n(_n), root(new Node()) {}
    void build() {
        build(1, n, root);
    }
    long long query(int l, int r) {
        return query(1, n, root, l, r);
    }
    void insert(int p, int k) {
        insert(1, n, root, p, k);
    }
};
struct Operate {
    int l, r;
    Operate(int _ = 0, int __ = 0) :
        l(_), r(__) {}
}Opt[N];
struct Element {
    int v, siz;
    Element(int _v = 0, int _s = 0) :
        v(_v), siz(_s) { }
    bool operator < (const Element& o) const {
        return v < o.v;
    }
}P[N];

int A[N], seq[N];

int main () {
    int n;
    scanf("%d", &n);
    int tot = 0;
    for (int i = 1, u, v, c; i <= n; i += 1) {
        scanf("%d%d", &u, &v);
        Opt[i] = Operate(u, v);
        A[++tot] = u, A[++tot] = v;
    }
    sort(A + 1, A + tot + 1);
    int cnt = unique(A + 1, A + tot + 1) - A - 1; // 被直接交換的位置, 也就是第一類
    int total = 0;
    for (int i = 1; i <= cnt; i += 1) {
        P[++total] = Element(A[i], 1); // 第一類
        if (A[i + 1] > A[i] + 1) // A[i] 和A[i+1]之間的是第三類
            P[++total] = Element(A[i] + 1, A[i + 1] - A[i] - 1);  // A[i+1]-A[i]-1是這一段的個數
    }
#define Find(x) lower_bound(P + 1, P + total + 1, Element(x, 0)) - P
    Tree* T = new Tree(total); // 建線段樹
    T->build();
    for (int i = 1; i <= total; i += 1)
        seq[i] = i;
    for (int i = 1, u, v; i <= n; i += 1) {
        u = Find(Opt[i].l), v = Find(Opt[i].r); // 按要求交換
        swap(seq[u], seq[v]);
    }
    long long res = 0;
    for (int i = 1; i <= total; i += 1) {
        T->insert(seq[i], P[seq[i]].siz); 
        res += 1ll * P[seq[i]].siz * T->query(seq[i] + 1, total);
    }
    printf("%lld\n", res);
    return 0;
}
相關文章
相關標籤/搜索