树状数组求逆序对

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树状数组求逆序对相关的知识,希望对你有一定的参考价值。

我果然还是太NAIVE了

一直没有学到这么搞基的求逆序对数方法

其实就是有点像计数排序

先开一个巨大的树状数组

然后插入一个数的时候看一下SUM

用当前位置减一下SUM就可以了

//其实就是求和

技术分享
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 #include <cstdlib>
 5 #include <cstring>
 6 #include <cmath>
 7 using namespace std;
 8 long long read() {
 9     long long x = 0, f = 1; char ch = getchar();
10     while (!isdigit(ch)) {
11         if (ch == -) f = -1; ch = getchar();
12     }
13     while (isdigit(ch)) {
14         x = x * 10 + ch - 0; ch = getchar();
15     }
16     return x * f;
17 }
18 
19 /*------------------------------template------------------------------*/
20 
21 #define nxt(x) (x & -x)
22 #define M 500050
23 typedef pair<int, int> pr;
24 int a[M << 1];
25 long long ans = 0;
26 int c[M], b[M];
27 int main () {
28     int n = read(), x;
29         memset(c, 0, sizeof(c));
30         memset(a, 0, sizeof(a));
31         for (int i = 1; i <= n; i ++) {
32             b[i] = c[i] = read();
33         }
34         sort(b + 1, b + 1 + n);
35         int tot = unique(b + 1, b + 1 + n) - b;
36         for (int i = 1; i <= n; i ++) {
37             c[i] = lower_bound(b + 1, b + tot, c[i]) - b;
38         }
39         for (int i = 1; i <= n; ans += i ++) {
40             x = c[i];
41             for (int j = x; j <= n; j += nxt(j)) {
42                 a[j] ++;
43             }
44             for (int j = x; j > 0; j -= nxt(j)) {
45                 ans -= a[j];
46             }
47             //printf("%d %d %d\n", x, i, ans);
48         }
49         printf("%lld\n", ans); //打成%d调了半天23333333
50     return 0;
51 }
Codevs求逆序对

于是就可以去做http://www.lydsy.com/JudgeOnline/problem.php?id=2141了哈哈哈

终于码完了23333

由于代码能力还不够最后还是对着调的。。。

题解:http://blog.csdn.net/PoPoQQQ/article/details/40373903

技术分享
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 long long read() {
 4     long long x = 0, f = 1; char ch = getchar();
 5     while (!isdigit(ch)) {
 6         if  (ch == -) f = -1; ch = getchar();
 7     }
 8     while (isdigit(ch)) {
 9         x = x * 10 + ch - 0; ch = getchar();
10     }
11     return x * f;
12 }
13 
14 /*------------------------------template------------------------------*/
15  
16 #define M 20200  
17 #define nxt(x) (x & -x)
18 using namespace std;
19 
20 int n, m, ans, tot, block;
21 int a[M];  
22 pair<int, int> b[M];
23 int pre[M], cnt[200][M];
24 
25 void up(int c[], int x) {  
26     for(; x <= n; x += nxt(x)) ++c[x];  
27 }
28 
29 void down(int c[], int x) {  
30     for(; x <= n; x += nxt(x)) --c[x];  
31 }
32 
33 int calc(int c[], int x) {  
34     int re = 0;  
35     for(; x; x -= nxt(x)) re+=c[x]; 
36     return re;
37 }
38 
39 int main() {  
40     int x, y;  
41     n = read();  
42     for(int i = 1; i <= n; i ++) b[i] = make_pair(read(), i);  
43     sort(b + 1, b + n + 1);
44     for(int i = 1; i <= n; i ++) {  
45         if (b[i].first != b[i - 1].first) ++tot;
46         a[b[i].second] = tot;
47     }
48     for(int i = n; i; i --) ans += calc(pre, a[i] - 1), up(pre, a[i]);  
49     printf("%d\n", ans);
50     //Get the first ans  
51     block = static_cast<int>(sqrt(n) + 1e-7);
52     for(int i = 1; i <= n; i ++) up(cnt[(i-1) / block], a[i]);
53     //Blocking init
54     m = read();
55     for(int i = 1; i <= m; i ++) {  
56         x = read(); y = read();
57         if (x > y) swap(x, y);
58         //查询(x, y)区间内有多少个数比a[x]和a[y]小  
59         int b1 = (x - 1) / block + 1;  
60         int b2 = (y - 1) / block - 1;  
61         if (b1 <= b2) {  
62             for(int j = b1; j <= b2; j ++) {  
63                 ans -= calc(cnt[j], a[x] - 1);  
64                 ans += calc(cnt[j], n) - calc(cnt[j], a[x]);  
65                 ans += calc(cnt[j], a[y] - 1);  
66                 ans -= calc(cnt[j], n) - calc(cnt[j], a[y]);  
67             }  
68             for(int j = x + 1; j <= b1 * block; j ++) {  
69                 if (a[j] < a[x]) --ans;  
70                 if (a[j] > a[x]) ++ans;  
71                 if (a[j] < a[y]) ++ans;  
72                 if (a[j] > a[y]) --ans;  
73             }  
74             for(int j = (b2 + 1) * block + 1; j < y; j ++) {  
75                 if (a[j]<a[x]) --ans;  
76                 if (a[j]>a[x]) ++ans;  
77                 if (a[j]<a[y]) ++ans;  
78                 if (a[j]>a[y]) --ans;  
79             }  
80         }  
81         else {
82             //暴力
83             for(int j = x + 1; j <= y - 1; j ++) {  
84                 if (a[j] < a[x]) --ans;  
85                 if (a[j] > a[x]) ++ans;  
86                 if (a[j] < a[y]) ++ans;  
87                 if (a[j] > a[y]) --ans;  
88             }  
89         }  
90         if (a[x] < a[y]) ++ans;  
91         else if (a[x] > a[y]) --ans;  
92         printf("%d\n", ans);  
93         down(cnt[(x-1) / block], a[x]);  
94         down(cnt[(y-1) / block], a[y]);  
95         swap(a[x], a[y]);
96         up(cnt[(x-1) / block], a[x]);  
97         up(cnt[(y-1) / block], a[y]);  
98     }  
99 }  
BZOJ2141

 

以上是关于树状数组求逆序对的主要内容,如果未能解决你的问题,请参考以下文章

树状数组求逆序对

HDU 1394 Minimum Inversion Number (树状数组求逆序对)

树状数组求逆序对

求逆序对(树状数组)

Another Version of Inversion 二维树状数组求逆序对

树状数组求逆序对