zoukankan      html  css  js  c++  java
  • 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
    ", ans1-ans2 );
    133         }
    134     }
    135     return 0;
    136 }
  • 相关阅读:
    WPF 本地化语言设置
    WPF 调节树状图滚动条值
    WPF中ListBox的使用注意事项
    SQL 树状结构表中查出所所有父级/子级
    Vue创建
    wpf 控件注意事项
    链表习题(1)-设计一个递归算法,删除不带头结点的单链表L中所有值为x的结点
    排序-快速排序
    排序-堆排序
    图-图的遍历
  • 原文地址:https://www.cnblogs.com/oneshot/p/4384639.html
Copyright © 2011-2022 走看看