POJ 2299 Ultra-QuickSort(树状数组+离散化+求逆序数)

简介: POJ 2299 Ultra-QuickSort(树状数组+离散化+求逆序数)

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
题意就是输入一个n,接着输入n个数,然后求出这n个数的逆序数。

最简单的求逆序数就是用冒泡排序,每次比较,如果交换说明整两个数是逆序的,ans++,也就是说冒泡排序交换次数就是逆序数;但是时间复杂度是O(n^2).
再就是可以用归并排序来求逆序数,隐隐约约记得之前做过一道题是可以的来求的,虽然现在忘了啊。
这里用树状数组来求。

先说离散化
如果数据量少,但是数据范围大,那么开数组的话会浪费很大一部分空间,所以需要离散化处理(通俗点就是把离散较大的数据紧凑起来)

for (int i=1; i<=n; i++){
   
    scanf("%d", &init[i].val);
    init[i].order=i;
}
sort(init+1, init+n+1, cmp);
for (int i=1; i<=n; i++)
    a[init[i].order]=i;

这样最后a数组的下标就是原来数据的元素的order位置,值就是被处理后的值。从而做到把离散的数据紧凑起来,节省空间。
这样就是把9 1 0 5 4变成5 2 1 4 3
再说求逆序数
这里用树状数组来求,就是每个元素的前面比它大的数量的和就是最终的逆序数。

在说明一点,i-sum(a[i])是本来一共有i个数,sum(a[i])是所有小于等于a[i]的个数,相减就是大于a[i]的个数,也就是在新的数前面大于它的元素的个数。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

int n;
int a[500005];
int c[500005];
struct node{
   
    int order;
    int val;
}init[500005];
int cmp(node a, node b){
   
    return a.val<b.val;
}
int lowbit(int x){
   
    return x&(-x);
}
void update(int index, int val){
   
    while (index<=n){
   
        c[index]+=val;
        index+=lowbit(index);
    }
}
int sum(int index){
   
    int ans=0;
    while (index>=1){
   
        ans+=c[index];
        index-=lowbit(index);
    }
    return ans;
}
int main(){
   
    while (scanf("%d", &n) && n){
   
        for (int i=1; i<=n; i++){
   
            scanf("%d", &init[i].val);
            init[i].order=i;
        }
        sort(init+1, init+n+1, cmp);
        for (int i=1; i<=n; i++)
            a[init[i].order]=i;
        memset(c, 0, sizeof(c));
        long long ans=0;
        for (int i=1; i<=n; i++){
   
            update(a[i], 1);
            ans+=(i-sum(a[i]));
        }
        printf("%lld\n", ans);
    }
    return 0;
}
相关文章
|
人工智能 安全 API
如何在数字世界复刻一个高还原、高拟真的“你”
通过阿里云智能媒体服务IMS完成数字人形象训练、人声克隆定制,并使用Timeline实现视频合成及创作,打造一个“声形俱佳”的数字分身。
957 0
|
2月前
|
SQL JSON 移动开发
SQL派生表优化实战:从物化机制到LATERAL JOIN的完整进阶
很多人只知道“子查询改JOIN就快了”,但不知道为什么,也不知道什么时候该改、什么时候不该改。本文从派生表的物化机制出发,拆解临时表膨胀、索引失效的根因,通过真实案例对比派生表、CTE、LATERAL JOIN三种写法的性能差异,帮助读者从“知道现象”升级到“理解原理”。
|
7月前
|
安全 Android开发 Windows
【安卓端+电脑端】怎么阻止手机弹窗广告?一键关闭弹窗广告软件推荐,你能接受办公软件有弹窗广告吗?如何屏蔽弹窗广告?
AdGuard是一款跨平台广告拦截工具,支持电脑、手机、TV及浏览器插件。一键开启即可屏蔽弹窗、网页广告及电视广告,内置家长控制、黑白名单与自定义过滤规则,有效净化网络环境。(239字)
2123 7
|
机器学习/深度学习 自然语言处理 PyTorch
基于Pytorch Gemotric在昇腾上实现GAT图神经网络
本实验基于昇腾平台,使用PyTorch实现图神经网络GAT(Graph Attention Networks)在Pubmed数据集上的分类任务。内容涵盖GAT网络的创新点分析、图注意力机制原理、多头注意力机制详解以及模型代码实战。实验通过两层GAT网络对Pubmed数据集进行训练,验证模型性能,并展示NPU上的内存使用情况。最终,模型在测试集上达到约36.60%的准确率。
|
算法
关于Dijkstra算法
关于Dijkstra算法
488 0
|
存储 SQL 关系型数据库
实时计算 Flink版操作报错合集之报错:WARN (org.apache.kafka.clients.consumer.ConsumerConfig:logUnused)这个错误如何解决
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
861 3
|
程序员
程序员必知:原码、反码、补码和移码详解
程序员必知:原码、反码、补码和移码详解
1879 0
|
编解码 Android开发 开发者
dp(相对大小) 和 px(像素)之间的相互转换
dp(相对大小) 和 px(像素)之间的相互转换
602 4
|
存储 Java
|
小程序
深入理解 uni-app 页面生命周期(四)onShareAppMessage
深入理解 uni-app 页面生命周期(四)onShareAppMessage
2281 0

热门文章

最新文章