zoukankan      html  css  js  c++  java
  • 用树状数组求逆序对数(poj2299)

    Ultra-QuickSort
    Time Limit: 7000MS   Memory Limit: 65536K
    Total Submissions: 46995   Accepted: 17168

    Description

    In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swapping two adjacent sequence elements until the sequence is sorted in ascending order. For the input sequence 
    9 1 0 5 4 ,

    Ultra-QuickSort produces the output 
    0 1 4 5 9 .

    Your task is to determine how many swap operations Ultra-QuickSort needs to perform in order to sort a given input sequence.

    Input

    The input contains several test cases. Every test case begins with a line that contains a single integer n < 500,000 -- the length of the input sequence. Each of the the following n lines contains a single integer 0 ≤ a[i] ≤ 999,999,999, the i-th input sequence element. Input is terminated by a sequence of length n = 0. This sequence must not be processed.

    Output

    For every input sequence, your program prints a single line containing an integer number op, the minimum number of swap operations necessary to sort the given input sequence.

    Sample Input

    5
    9
    1
    0
    5
    4
    3
    1
    2
    3
    0
    

    Sample Output

    6
    0
    

    Source

               题目大意:给定若干个序列,假设是a[],求满足a[i]>a[j],且0<=i<j<=N的i,j的对数。
               首先,暴力的方法应该很好想,只要枚举每一个a[i],在枚举a[j](0<j<=i-1),若a[j]>a[i],则ans++。
              
               但是,这题给的序列的长度达到50w,若用暴力,时间复杂度为O(n^2),时间上过不了。为此可以针对这个序列中的数字大小区间做一个树状数组,按顺序把序列元素加进去,统计比它小的数字的个数,累加起来即可,时间复杂度O(nlogn),轻松通过。
     
               再但是,每个数字大小达到近百亿,若针对每个数字建立一个树状数组,空间上开不下(题目上只给了64M内存),所以要用离散化来解决(离散化讲解:http://baike.baidu.com/view/3392254.htm)具体方法是:先用结构体暂时存储序列,记下大小和位置,然后快排一下(虽然快排在序列完全逆序时可能卡到O(n^2),但应该不会在这里卡),再开一个reflect[],记录下离散化后的序列,这样若有50w个数,即使都很大,也终究有个大小之分,可以离散成1~50w,数组开至百万完全无压力。。
             
               就这样,时间和空间的问题都解决了。。。
     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstdlib>
     4 #include<algorithm>
     5 #include<cmath>
     6 using namespace std;
     7 typedef long long LL;
     8 int N,M;
     9 struct node{
    10     int val;//记录大小 
    11     int pos;//记录这个数字的位置,方便以后排序 
    12 };
    13 node a[1000000];//暂时存储序列 
    14 int reflect[1000000];//离散化后的序列  
    15 int BIT[10000000];//树状数组 
    16 
    17 int cmp(const node &u,const node &v){
    18     if(u.val<v.val) return 1;
    19     return 0;
    20 }
    21 
    22 int lowbit(int x){
    23     return x&(-x);
    24 }
    25 /*
    26 update 
    27 把数字依次插入,而不是直接建树的原因: 
    28 我们目的是求之前比当前数字小的数字个数,这样可以做到
    29 ans+=i-sum(reflect[i])来更新,直接建树。。。不行 
    30 */
    31 
    32 void update(int x){
    33     for(int i=x;i<=N;i+=lowbit(i)){
    34         BIT[i]++;
    35     }
    36 }
    37 
    38 int sum(int k){
    39     int ANS=0;
    40     for(int i=k;i>0;i-=lowbit(i)){
    41         ANS+=BIT[i];
    42     }
    43     return ANS;
    44 }
    45 int main(){
    46     while(scanf("%d",&N)!=EOF&&N){
    47        for(int i=1;i<=N;i++){
    48            scanf("%d",&a[i].val);
    49            a[i].pos=i;
    50            }
    51        sort(a+1,a+N+1,cmp);
    52     
    53        for(int i=1;i<=N;i++)
    54            reflect[a[i].pos]=i;//离散化 
    55        for (int i = 1; i <= N; ++i) BIT[i] = 0;
    56           //清空树状数组,,,千万不要忘记
    57         LL ans=0;
    58         for(int i=1;i<=N;i++){
    59         update(reflect[i]);
    60         ans+=(i-sum(reflect[i]));
    61         }
    62         printf("%lld
    ",ans);
    63     }
    64 
    65     return 0;
  • 相关阅读:
    mysql 修改表
    mac下安装MySQL 5.7
    win&linux下path中%%与$ 以及;与:区别,
    PATH
    转 path设置方式
    MyEclipse乱码问题
    03 最大的数据库 information_schema介绍以及sql注入第一题题解
    02.mysql数据库 基本命令
    01.Windows进入MySQL数据库
    Web web4
  • 原文地址:https://www.cnblogs.com/CXCXCXC/p/4626604.html
Copyright © 2011-2022 走看看