P1908 逆序对——归并算法

先吐槽


这题做了两天,昨天讲分治,老师用归并讲了一遍,今天又用树状数组讲了一遍

归并不难,啊啊啊我居然才调出来

思路

  归并两个数组时,对于第二个数组的元素a[c2],它与第一个数组中目前还没归到总数组里的元素形成逆序对

  c1,c2是指针,对于a[c2],它与a[c1..mid]构成逆序对,贡献{mid - c1 + 1}对

注意

  ans开longlong,不然会WA一半!

  临时数组c开成全局变量,函数里放不下

两种记录方式

  >函数不返回值,ans开成全局变量,在每次归并两个数组时增加对数

  >函数返回值,ans开在函数里,赋值递归两个分数组的返回值之和,再加上归并两个数组时的对数

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>

using namespace std;

long long n , ans;
int a[500005] , c[500010];
long long back(int l , int r)
{
if(l == r)
return 0;
int mid = l + (r - l) / 2;
long long ans = back(l , mid);
ans += back(mid + 1 , r);
int c1 = l , c2 = mid + 1 , top = l;//c[500010]太大,只能开全局
while (c1 <= mid && c2 <= r)
{
if(a[c1] <= a[c2])
c[top++] = a[c1++];
else
{
c[top++] = a[c2++];
ans += mid - c1 + 1;
}

}
while (c1 <= mid)
c[top++] = a[c1++];
while (c2 <= r)
c[top++] = a[c2++];
for (int i = l ; i <= r ; i++)
a[i] = c[i];
return ans;
}

int main()
{
cin >> n;
for (int i = 1 ; i <= n ; i++)
{
cin >> a[i];
}
ans = back(1 , n);
cout << ans << endl;
return 0;
}

原文地址:https://www.cnblogs.com/ZhengkunJia/p/12210701.html

时间: 2024-11-12 06:05:10

P1908 逆序对——归并算法的相关文章

luogu P1908 逆序对

二次联通门 : luogu P1908 逆序对 /* luogu P1908 逆序对 权值线段树 + 离散化 + 指针版线段树... 把所有数离散化后将其作为下标建空树 对于每次插入的数字x, 查找x+1到max区间的数字存在的个数, 并将这个个数加入答案, 然后插入这个数字 最后输出答案 %%Menci的线段树...6到一定境界了... */ #include <algorithm> #include <cstdio> #define Max 40080 void read (i

O(n*lgn)时间复杂度的逆序对统计算法实现思想

逆序对定义:设A[1..n]是一个包含n个不同数的数组.如果在i<j的情况下,有A[i] > A[j],则(i,j)就称为A中的一个逆序对(inversion). 现给出一个算法,其可以用O(n*lgn)的最坏情况运行时间,确定n个元素的任何排列中逆序对的数量. 简单的算法实现思想:我们可以单纯的通过从前往后的逐一比对来确定逆序对的数量,虽然实现简单,但这样一来时间复杂度将会上升为O(n*n),不符合我们的要求. 改进的算法实现思想:众所周知归并排序的时间复杂度为O(cn*lgn + cn),

洛谷 P1908 逆序对 Label:归并排序||树状数组

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

P1908 逆序对-(cdq分治)

https://www.luogu.org/problem/P1908 沿用归并排序的思想求逆序对. 坑1:结果爆int型,需要用longlong 坑2:相对于归并排序,在比较的时候多了一个等号 举例说明归并排序解本题,例如有6个数, 36,87,99,   左区间范围是l到mid,下标用t1表示 1,2,50,     右区间范围是mid+1到r,下标用t2表示 分成2堆,两堆排好序,要合并.此时l=1,mid=3,t1=1; mid+1=4,r=6,t2=4; 比较36和1,选1,则左边还没

P1908 逆序对-(树状数组)

https://www.luogu.org/problem/P1908 比较喜欢线段树,懒得用树状数组(只会套模板,位运算的精髓没有领悟到),一直没有记录树状数组代码,又得捡回来,趁这道题记录一下模板,为三维偏序cdq套树状数组铺垫一下. 解题思路:先对原数组a从大到小排序,依次添加进树状数组c里,每次求前缀和的结果就是 当前数的逆序对的个数. 例如数据:55,44,22,66,33,11 初始化树状数组c,清0: 添加66到4号位,则添加数组为 0,0,0,1,0,0: 66前没有比它大的数,

洛谷 P1908 逆序对

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

[洛谷P1908] 逆序对

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

luogu P1908 逆序对 |树状数组

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

P1908 逆序对

就是在归并排序的基础上加一点小操作,还是很容易实现的,感觉和线段数长得很像qwq. 也没什么可说的了,直接上代码啦: #include<cstdio> #include<iostream> #include<algorithm> using namespace std; const int maxn=5e5+5; int n,a[maxn]; long long ans; void merge(int l,int r) { if(l==r) return ; int m