• 计蒜客模拟赛D2T2 蒜头君的排序:区间逆序对(移动端点) + 树状数组


    题目链接:https://nanti.jisuanke.com/t/16443

    题意:

      给你一个由1~n构成的正整数序列,有m组询问,每组询问要求输出[l , r]区间内的逆序对个数。

    数据范围:

      对于100%的数据,满足1 <= n,m <= 30000,l < r,∑ | l[i] - l[i-1] | + ∑ | r[i] - r[i-1] | <= 7 * 10^6。

    题解:

      如果知道区间[l , r]中的逆序对个数,那么也可以快速求出区间[l-1 , r],[l+1 , r],[l , r-1],[l , r+1]的逆序对个数。

      ① [l-1 , r]的个数 = [l , r]的个数 + [l , r]中比a[l-1]小的元素的个数

      ② [l+1 , r]的个数 = [l , r]的个数 - [l+1 , r]中比a[l]小的元素的个数

      ③ [l , r-1]的个数 = [l , r]的个数 - [l , r-1]中比a[r]大的元素的个数

      ④ [l , r+1]的个数 = [l , r]的个数 + [l , r]中比a[r+1]大的元素的个数

      查询区间内比x大(小)的元素的个数用树状数组实现。

      比x大的元素个数 = query(x - 1)

      比x小的元素个数 = query(n) - query(x)  (区间内元素总个数减去大于等于x的元素个数)

      先假定现在的区间为[1 , 1],逆序对总个数为0。对于每一组询问,只要不断移动当前区间的左右端点,并同时更新答案,直至当前区间与询问区间相同即可,输出sum值。

    AC Code:

     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <string.h>
     4 #define MAX_N 30005
     5 
     6 using namespace std;
     7 
     8 int n,m;
     9 int a[MAX_N];
    10 int dat[MAX_N];
    11 
    12 void update(int k,int a)
    13 {
    14     while(k<=n)
    15     {
    16         dat[k]+=a;
    17         k+=k&-k;
    18     }
    19 }
    20 
    21 int query(int k)
    22 {
    23     int sum=0;
    24     while(k>0)
    25     {
    26         sum+=dat[k];
    27         k-=k&-k;
    28     }
    29     return sum;
    30 }
    31 
    32 void read()
    33 {
    34     cin>>n;
    35     for(int i=1;i<=n;i++)
    36     {
    37         cin>>a[i];
    38     }
    39 }
    40 
    41 void solve()
    42 {
    43     memset(dat,0,sizeof(dat));
    44     cin>>m;
    45     int sum=0;
    46     int lef=1,rig=1;
    47     update(a[1],1);
    48     for(int i=0;i<m;i++)
    49     {
    50         int l,r;
    51         cin>>l>>r;
    52         while(lef<l)
    53         {
    54             update(a[lef],-1);
    55             sum-=query(a[lef]-1);
    56             lef++;
    57         }
    58         while(lef>l)
    59         {
    60             lef--;
    61             sum+=query(a[lef]-1);
    62             update(a[lef],1);
    63         }
    64         while(rig<r)
    65         {
    66             rig++;
    67             sum+=query(n)-query(a[rig]);
    68             update(a[rig],1);
    69         }
    70         while(rig>r)
    71         {
    72             update(a[rig],-1);
    73             sum-=query(n)-query(a[rig]);
    74             rig--;
    75         }
    76         cout<<sum<<endl;
    77     }
    78 }
    79 
    80 int main()
    81 {
    82     read();
    83     solve();
    84 }
  • 相关阅读:
    告别alert,拥抱console
    LeetCode之Max Points on a Line Total
    LeetCode之Maximum Product Subarray
    LeetCode之Reverse Words in a String
    LeetCode之Min Stack
    MySQL之系系统信息函数
    MySQL之日期时间函数
    MysqL之数值函数
    XML文件解析之JDOM解析
    XML文件解析之DOM4J解析
  • 原文地址:https://www.cnblogs.com/Leohh/p/7263354.html
Copyright © 2020-2023  润新知