题意查询给定[L, R]区间内 逆序对数 ==k的子区间的个数。
我们只需要求出 子区间小于等于k的个数和小于等于k-1的个数,然后相减就得出答案了。
对于i(1≤i≤n),我们计算ri表示[i,ri]的逆序对数小于等于K,且ri的值最大。(ri对应代码中的cnt数组)
显然ri单调不降,我们可以通过用两个指针扫一遍,利用树状数组计算出r数组。
对于每个询问L,R,我们要计算的是∑i=LR[min(R,ri)−i+1]
由于ri具有单调性,那我们直接在上面二分即可,然后记一个前缀和(s数组)。
1 #include <set> 2 #include <map> 3 #include <cmath> 4 #include <ctime> 5 #include <queue> 6 #include <stack> 7 #include <cstdio> 8 #include <string> 9 #include <vector> 10 #include <cstdlib> 11 #include <cstring> 12 #include <iostream> 13 #include <algorithm> 14 using namespace std; 15 typedef unsigned long long ull; 16 typedef long long ll; 17 const int inf = 0x3f3f3f3f; 18 const double eps = 1e-8; 19 const int maxn = 1e5+100; 20 int n, q, tot, a[maxn]; 21 ll k, vec[maxn]; 22 int lowbit (int x) 23 { 24 return x & -x; 25 } 26 ll arr[maxn]; 27 int M ; 28 void modify(int x, int d) 29 { 30 while (x < M) 31 { 32 arr[x] += d; 33 x += lowbit(x); 34 } 35 } 36 ll sum(int x) 37 { 38 ll res = 0; 39 while (x) 40 { 41 res += arr[x]; 42 x -= lowbit(x); 43 } 44 return res; 45 } 46 ll cnt[2][maxn]; 47 ll s[2][maxn]; 48 ll solve (int L, int R, ll x, int w) // 小于等于x的数量 49 { 50 if (x < 0) 51 return 0; 52 //int tmp = 0; 53 int tmp = lower_bound(cnt[w]+L, cnt[w]+R+1, (ll)R) - cnt[w]; 54 while (tmp >= R+1) // cnt数组中所有数都小于 R时,,得到的tmp是大于R+1的 55 tmp--; 56 while (cnt[w][tmp] > R && tmp >= L) 57 tmp--; 58 if (tmp < L) 59 return (ll)R*(ll)(R-L+1) - (ll)(L+R)*(ll)(R-L+1)/2; 60 return s[w][tmp] - s[w][L-1] - (ll)(R-tmp)*(ll)(R+tmp+1)/2+ (ll)(R-tmp)*(ll)R; 61 } 62 int main() 63 { 64 #ifndef ONLINE_JUDGE 65 freopen("in.txt","r",stdin); 66 freopen("out.txt", "w", stdout); 67 #endif 68 while (~scanf ("%d%d%I64d", &n, &q, &k)) 69 { 70 M = n + 10; 71 memset(arr, 0, sizeof (arr)); 72 memset(cnt, 0, sizeof (cnt)); 73 memset(s, 0, sizeof(s)); 74 for (int i = 0; i < n; i++) 75 { 76 scanf ("%I64d", vec+i); 77 a[i] = vec[i]; 78 } 79 sort (vec, vec+n); 80 tot = unique(vec, vec+n) - vec; 81 for (int i = 0; i < n; i++) 82 { 83 a[i] = lower_bound(vec, vec+tot, a[i]) - vec + 2; //离散化 84 } 85 ll res = 0; 86 //小于等于k 87 for (int i = 0, j = 0; i < n; i++) 88 { 89 for ( ; j < n && res <= k; j++) 90 { 91 res += (j - i) - sum(a[j]); 92 modify(a[j], 1); 93 } 94 if (res >= k) 95 cnt[1][i] = (res > k ? max(0,j -1-1): j-1) ; // -1是因为 j先加了一下, 才跳出 循环的 96 else 97 cnt[1][i] = j-1-1; 98 s[1][i] = s[1][i-1] + cnt[1][i] - (i); 99 modify(a[i], -1); 100 res -= sum(a[i]-1); 101 } 102 103 //小于等于k-1 104 res = 0; 105 for (int i = 0, j = 0; i < n; i++) 106 { 107 for ( ; j < n && res <= (k-1); j++) 108 { 109 res += (j-i) - sum(a[j]); 110 modify(a[j], 1); 111 } 112 if (res >= k-1) 113 cnt[0][i] = (res > (k-1) ? max(j-1-1,0) : j-1); 114 else 115 cnt[0][i] = j-1-1; 116 117 s[0][i] = s[0][i-1] + cnt[0][i] - (i); 118 modify(a[i], -1); 119 res -= sum(a[i]-1); 120 } 121 for (int i = 0; i < q; i++) 122 { 123 int u, v; 124 scanf ("%d%d", &u, &v); 125 u--, v--; 126 if (u > v) 127 swap(u, v); 128 ll ans1 = solve(u, v, k, 1); 129 ll ans2 = solve(u, v, k-1, 0); 130 if (k == 0) 131 ans1 += (v-u+1); // 考虑形如[a, a]的区间 132 printf("%I64d\n", ans1-ans2 ); 133 } 134 } 135 return 0; 136 }