zoukankan      html  css  js  c++  java
  • 归并排序/树状数组求逆序对-lgP1908 逆序对

    1、归并排序逆序对

    (1) 归并排序的过程(看到一篇知乎写的特别好,链接

    整个过程大概就是不断把一个区间分成两个区间,直到分成单位区间,两个区间不断有序的合并,知道最后形成一个完整的有序的区间。

    (2)归并排序的应用:求逆序对:

    改动的地方在于:左右两部分的有序序列合并时,假设i在左边,j在右边,对于右边的j,统计左边比它大的元素个数f(j),则f(j) = mid-i+1 ,合并万所有的序列时即可得出答案,即f(j)之和便是答案(其实我自己都不是很理解)

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <algorithm>
     4 #define ll long long
     5 using namespace std;
     6 const int maxn=5e5+100;
     7 ll n,a[maxn],pos,c[maxn],ans;
     8 void merge_sort(ll l,ll r){
     9     if (l==r) return;
    10     else {
    11         ll mid=(l+r)>>1;
    12         merge_sort(l,mid);merge_sort(mid+1,r);
    13         ll i = l,j=mid+1;pos=l;
    14         while (i<=mid&&j<=r){
    15             if (a[i]<=a[j]) c[pos++]=a[i++];
    16             else{
    17                 c[pos++]=a[j++];
    18                 ans+=(mid-i+1);
    19             }
    20         }
    21         while (i<=mid) {c[pos]=a[i];pos++,i++;}
    22         while (j<=r) {c[pos]=a[j];pos++,j++;}
    23         for (ll k = l;k <= r;k++) a[k]=c[k];
    24     }
    25 }
    26 int main(){
    27     scanf ("%lld",&n);
    28     for (ll i = 1;i <= n;i++) scanf ("%lld",&a[i]);
    29     merge_sort(1,n);
    30     printf("%lld
    ",ans);
    31     return 0;
    32 }

    2、树状数组求逆序对

    (1)算法思路:树状数组维护数字的个数,因为逆序对的定义:对i<j有$a_i$>$a_j$,从这里我们可以看出,一个数的逆序对只与他后面位置的数有关系,所以我们需要从后往前加,然后在树桩数组里找比他小的数的个数。

    (2)注意:离散化,不太理解,会了再说

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <algorithm>
     4 #define ll long long
     5 using namespace std;
     6 const int maxn=5e5+10;
     7 ll n,a[maxn],b[maxn],ans,sum[maxn];
     8 void fix(ll x,ll k){
     9     for (ll i = x;i <= n;i+=i&(-i)) sum[i]+=k;
    10 }
    11 ll query(ll x){
    12     ll res=0;
    13     for (ll i = x;i >= 1;i-=i&(-i)) res+=sum[i];
    14     return res;
    15 }
    16 void init(){
    17     sort(b+1,b+1+n);
    18     unique(b+1,b+1+n)-b-1;
    19     for (ll i = 1;i <= n;i++) a[i]=lower_bound(b+1,b+n+1,a[i])-b;
    20 }
    21 int main(){
    22     scanf ("%lld",&n);
    23     for (ll i = 1;i <= n;i++) {scanf ("%lld",&a[i]);b[i]=a[i];}
    24     init();
    25     for(ll i = n;i >= 1;i--){
    26         fix(a[i],1);
    27         ans+=query(a[i]-1);
    28     }
    29     printf("%lld
    ",ans);
    30     return 0;
    31 }
  • 相关阅读:
    ubuntu安装jdk的两种方法
    LeetCode 606. Construct String from Binary Tree (建立一个二叉树的string)
    LeetCode 617. Merge Two Binary Tree (合并两个二叉树)
    LeetCode 476. Number Complement (数的补数)
    LeetCode 575. Distribute Candies (发糖果)
    LeetCode 461. Hamming Distance (汉明距离)
    LeetCode 405. Convert a Number to Hexadecimal (把一个数转化为16进制)
    LeetCode 594. Longest Harmonious Subsequence (最长的协调子序列)
    LeetCode 371. Sum of Two Integers (两数之和)
    LeetCode 342. Power of Four (4的次方)
  • 原文地址:https://www.cnblogs.com/very-beginning/p/13713484.html
Copyright © 2011-2022 走看看