POJ - 2299 - Ultra-QuickSort = 归并排序 + 逆序对 / 树状数组

http://poj.org/problem?id=2299

求逆序对最简单的绝对不会是树状数组,一定是归并排序(认真),不过树状数组会不会快一点呢?理论上应该是树状数组快一点(假如不进行离散化)。

#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<map>
#include<set>
#include<stack>
#include<string>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;

const int MAXN = 500000;
int a[MAXN + 5];
int tmp[MAXN + 5];

//分治,对[l,r]闭区间进行归并排序并统计逆序数
ll merge(int l, int r) {
    if(l == r)
        return 0;
    int m = (l + r) >> 1;
    ll res = 0;
    res += merge(l, m);
    res += merge(m + 1, r);
    int i = l, j = m + 1, k = 0;
    while(i <= m || j <= r) {
        if(i > m) {
            tmp[++k] = a[j++];
        } else if(j > r) {
            tmp[++k] = a[i++];
        } else {
            if(a[i] <= a[j]) {
                tmp[++k] = a[i++];
            } else {
                res += m + 1 - i;
                tmp[++k] = a[j++];
            }
        }
    }
    k = 0;
    for(int i = l; i <= r; ++i) {
        a[i] = tmp[++k];
    }
    return res;
}

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    int n;
    while(~scanf("%d", &n)) {
        if(n == 0)
            break;
        for(int i = 1; i <= n; ++i)
            scanf("%d", &a[i]);
        printf("%lld\n", merge(1, n));
    }
}

带离散化的树状数组果然常数大得不行。

#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<map>
#include<set>
#include<stack>
#include<string>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;

const int MAXN = 500000;
int a[MAXN + 5];
int x[MAXN + 5];
int bit[MAXN + 5];

int n;

void add(int x) {
    for(; x <= n; x += (x & -x))
        ++bit[x];
}

ll sum(int x) {
    ll res = 0;
    for(; x; x -= (x & -x))
        res += bit[x];
    return res;
}

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    while(~scanf("%d", &n)) {
        if(n == 0)
            break;
        memset(bit, 0, sizeof(bit[0]) * (n + 1));
        for(int i = 1; i <= n; ++i) {
            scanf("%d", &a[i]);
            x[i] = a[i];
        }
        sort(x + 1, x + 1 + n);
        int xt = unique(x + 1, x + 1 + n) - (x + 1);
        ll res = 0;
        for(int i = 1; i <= n; ++i) {
            a[i] = lower_bound(x + 1, x + 1 + xt, a[i]) - x;
            add(a[i]);
            res += i - sum(a[i]);
        }
        printf("%lld\n", res);
    }
}

原文地址:https://www.cnblogs.com/Inko/p/11729741.html

时间: 2024-10-13 05:13:36

POJ - 2299 - Ultra-QuickSort = 归并排序 + 逆序对 / 树状数组的相关文章

BZOJ3295 CQOI2011 动态逆序对 树状数组套线段树

离线倒着做,每次加入一个节点后新增的逆序对数量就是其左边大于它的数的个数(左边数的总数-左边小于它的数的个数)+右边小于它的数的个数 用树状数组维护求和,对于树状数组中每个节点v所对应的区间线段树维护区间[l,r]中大于v的数的个数. 最后唯一的问题就是指针版线段树MLE-- #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <alg

求逆序对[树状数组] jdoj

求逆序对 题目大意:给你一个序列,求逆序对个数. 注释:n<=$10^5$. 此题显然可以跑暴力.想枚举1到n,再求在i的后缀中有多少比i小的,统计答案即可.这显然是$n^2$的.这...显然过不去,我们思考如何优化?显然,这里的有些过程是重复的.我们将这个序列设为a序列,对于两个1到n中的整数i<j,在j后面的数我们进行了多次重复枚举,我们思考如何优化.容易想到用一个桶来记录.只需要记录对于每一个数来讲,我后面有多少个数是比我小的,只需要将桶中的数累加即可.但是,我们必须记录是这个数之后的桶

【2018.12.15】【考试总结】【模拟+逆序对+树状数组+贪心+multiset】爆零之旅

这是我悲惨的接近爆零的一次考试,但是本蒟蒻不能放弃,还是要总结的QAQ 答题卡 [题目背景] 八月是个悲惨的月份.先不谈炎热的天气,对于新生来说,八月意味着军训: 而对于高二高三的同学来说,八月意味着开学考试.而考试就意味着改卷,改卷 也就意味着答题卡.不幸的是,学校读答题卡的机器的评分软件坏了,wyx 就被 老师要求写一个评分的程序. [问题描述] 软件需要读入学生的姓名.试题答案以及学生的答题卡信息. 学生姓名 学校的信息管理系统中存储了所有学生的姓名,一共 名学生.每个学生的 名字的组成只

BZOJ 3295 [Cqoi2011]动态逆序对 树状数组套线段树

题意:链接 方法:树状数组套线段树 解析: 这题基本上写的都是什么CDQ点分治,主席树之类的,然而这我都并不会,所以写了一发平衡树套线段树想卡时卡过去,然而我并没有得逞,T的不要不要的,这里用平衡树套线段树的方法参见我的题解:排队.这道题比那道更要简单. 然后我就打算弃坑了~不过看140142做这道题做的热火朝天的,还是打算回来做一下,yy下树状数组套线段树,然后去看hz的题解,只看懂他写理论部分了,代码部分不知所云,所以还是还是得yy.引用理论部分. 删除某个数,只要统计它之前还存在的比它大的

luogu P1908 逆序对 |树状数组

题目描述 猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计.最近,TOM老猫查阅到一个人类称之为"逆序对"的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中ai>aj且i<j的有序对.知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目. Update:数据已加强. 输入格式 第一行,一个数n,表示序列中有n个数. 第二行n个数,表示给定的序列.序列中每个数字不超过10

poj 1195:Mobile phones(二维树状数组,矩阵求和)

Mobile phones Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 14489   Accepted: 6735 Description Suppose that the fourth generation mobile phone base stations in the Tampere area operate as follows. The area is divided into squares. The

POJ_3067 Japan[ 逆序数 树状数组 or 归并排序)

传送门:POJ_3067 题目:n,m,k;左右两列数,数的范围分别1-n,1-m,然给k个连线. Sample Input 1 3 4 4 1 4 2 3 3 2 3 1 Sample Output Test case 1: 5 思路:逆序数 代码: //树状数组版 //块状数组 #include<iostream> #include<cstring> #include<cmath> #include<cstdio> #include<algorit

POJ 1195 Mobile phones(二维树状数组)

题目链接:POJ 1195 题意: 给出一个S*S的矩阵(行.列号从1开始),每个元素初始值为0,有两种操作:一种是第X行第Y列元素值加A:另一种是查询给定范围矩阵的所有元素之和(L<=X<=R,B<=Y<=T). 分析: 查询给定范围矩阵的所有元素之和是二维区间和,可以转换为二维前缀和求值.类比一维前缀和求法,二维区间和S(L, B, R, T) = S(1, 1, R, T) - S(1 ,1, L-1, T) - S(1, 1, R, B-1) + S(1, 1, L-1,

poj 3468 A Simple Problem with Integers 树状数组 或 线段树

题目链接:http://poj.org/problem?id=3468 一般说来 树状数组是 [单点更新 区间查询] 而本题是“区间更新 区间查询” 所以要改成维护前缀和 推公式的过程见<挑战程序设计竞赛>第181~182面 代码中bit0是i的零次项 bit1是i的一次项 以后以此类推 在[l, r]加数的时候 写出公式 在l的地方 一次项及以上的直接写 然后在零次项那减去 在r的地方 一次项及以上的减掉之前加上的 然后再零次项那加上“公式化简之后的最终结果 减去 之前在零次项加的那一项”