小 a有一個長度無限長的序列 p = (1, 2, 3, 4 ……),初始時 pi = i
給出 m 個操做,每次交換兩個位置的數
詢問最後序列逆序對的個數node
忘了能夠樹狀數組直接作了.因此寫了很麻煩的線段樹.
大概寫一下怎麼作, 由於細節比較多.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
#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; }