分析:其实就是求m个区间的逆序对个数,题目真的是明摆着让我们用莫队算法,套用树状数组就可以了.
具体怎么转移呢?如果移动R,那么对区间[l,r]有影响的是R左边的元素,我们只需要看有多少在R左边比a[R]大的元素就可以了.如果移动L,对[l,r]有影响的是L右边的元素,并且比a[L]小,我们在移动L的时候看看有多少比a[L]小就可以了.
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <cmath> using namespace std; int n,a[30010],m,sizee,L = 1,R = 0,ans,c[300010],sum[30010]; struct node { int l, r, id; }e[30010]; int query(int x) { int res = 0; while (x) { res += c[x]; x -= x & (-x); } return res; } void add(int x, int v) { while (x <= n) { c[x] += v; x += x & (-x); } } bool cmp(node a, node b) { if (a.l / sizee == b.l / sizee) return a.r < b.r; return a.l < b.l; } int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); sizee = sqrt(n); scanf("%d", &m); for (int i = 1; i <= m; i++) { scanf("%d%d", &e[i].l, &e[i].r); e[i].id = i; } sort(e + 1, e + 1 + m, cmp); for (int i = 1; i <= m; i++) { while (R < e[i].r) { ans += query(n) - query(a[++R] - 1); add(a[R], 1); } while (R > e[i].r) { add(a[R], -1); ans -= query(n) - query(a[R--] - 1); } while (L < e[i].l) { add(a[L], -1); ans -= query(a[L++] - 1); } while (L > e[i].l) { ans += query(a[--L] - 1); add(a[L], 1); } sum[e[i].id] = ans; } for (int i = 1; i <= m; i++) printf("%d\n", sum[i]); return 0; }