HDU5196--DZY Loves Inversions 树状数组 逆序数

题意查询给定[L, R]区间内 逆序对数 ==k的子区间的个数。

我们只需要求出 子区间小于等于k的个数和小于等于k-1的个数,然后相减就得出答案了。

对于i(1in),我们计算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 }

 

你可能感兴趣的:(version)