BZOJ 3289:Mato的文件管理(莫队算法+树状数组)
http://www.lydsy.com/JudgeOnline/problem.php?id=3289
题意:……
思路:求交换次数即求逆序对数。确定了这个之后,先离散化数组。然后在后面插入元素的话,就是在区间里面找比它大的元素数量,在前面插入元素的话,就是在区间里面找比它小的元素数量。删除操作类似。因为排序是从小到大排序,所以要找比它大的数量就是区间长度减去小于等于该元素的数量,所以是(R - L + 1 - sum(a[i])),要找比它小的数量就是(sum(a[i] - 1))。然后用莫队算法处理区间询问就好了。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <cmath> 5 using namespace std; 6 #define N 50010 7 struct node { 8 int l, r, id, ans; 9 } p[N]; 10 int bit[N], a[N], b[N], num[N], ans, kuai, n; 11 12 bool cmp(const node &a, const node &b) { 13 if(a.l / kuai == b.l / kuai) return a.r < b.r; 14 return a.l / kuai < b.l / kuai; 15 } 16 bool cmpid(const node &a, const node &b) { return a.id < b.id; } 17 int lowbit(int x) { return x & (-x); } 18 void add(int x, int w) { for( ; x <= n; x += lowbit(x)) bit[x] += w; } 19 int sum(int x) { int ans = 0; for( ; x ; x -= lowbit(x)) ans += bit[x]; return ans; } 20 21 int main() { 22 while(~scanf("%d", &n)) { 23 for(int i = 1; i <= n; i++) scanf("%d", &a[i]), b[i] = a[i]; 24 int q; scanf("%d", &q); 25 for(int i = 1; i <= q; i++) scanf("%d%d", &p[i].l, &p[i].r), p[i].id = i; 26 27 memset(bit, 0, sizeof(bit)); 28 ans = 0; kuai = sqrt(n); 29 sort(b + 1, b + 1 + n); 30 int cnt = unique(b + 1, b + 1 + n) - b - 1; 31 for(int i = 1; i <= n; i++) a[i] = lower_bound(b + 1, b + 1 + cnt, a[i]) - b; 32 33 sort(p + 1, p + 1 + q, cmp); 34 for(int L = 1, R = 0, i = 1; i <= q; i++) { 35 int l = p[i].l, r = p[i].r; 36 for( ; L < l; L++) { ans -= sum(a[L] - 1); add(a[L], -1); } 37 for( ; L > l; L--) { ans += sum(a[L-1] - 1); add(a[L-1], 1); } 38 for( ; R < r; R++) { ans += R - L + 1 - sum(a[R+1]); add(a[R+1], 1); } 39 for( ; R > r; R--) { ans -= R - L + 1 - sum(a[R]); add(a[R], -1); } 40 p[i].ans = ans; 41 } 42 sort(p + 1, p + 1 + q, cmpid); 43 for(int i = 1; i <= q; i++) printf("%d\n", p[i].ans); 44 } 45 return 0; 46 }