Poj2299 Ultra-QuickSort(另附本质不同逆序对)
Description
求至少需要多少次交换才能把 a 从小到大排序。
Input
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
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
线段树大法好!
我一个不会离散化的蒟蒻在wa了6遍后终于学会了看题,然后苦逼的发现了999999999才是真正的数据范围
只好向旁边的大佬请教离散化
没想到还挺简单的,很短:
for(int i=;i<=n;i++)scanf("%d",&x[i].num),x[i].id=i;
sort(x+,x+n+,cmp);
for(int i=;i<=n;i++)a[x[i].id]=i;
其实就是把原来的数排序,然后按照大小关系安上新的值。
别看此题说的有多玄学,其实就是逆序对
举个例子吧:
1 2 3 4 5 6 7 8是个有序的数列,假如把3和8调换位置
得到1 2 8 4 5 6 7 3,此时逆序对的个数是5,仔细观察是不是只要5步就可以有序
理性的我讲不出,但是你现在是不是可以感性的理解为什么是逆序对的个数了
所以先离散化处理一下,线段树跑一遍逆序对就行了
代码(long long也是坑点):
#include<cstdio>
#include<algorithm>
using namespace std;
int n,m,a[];
long long ans;
struct o{int num,id;}x[];
struct oo{int a,b,v;}s[];
bool cmp(o a,o b)
{
return a.num<b.num;
}
void build(int x,int l,int r)
{
s[x].a=l,s[x].b=r;s[x].v=;
if(l==r)return ;
build(x<<,l,l+r>>);
build(x<<|,(l+r>>)+,r);
}
void change(int x,int y)
{
s[x].v++;
if(s[x].a==s[x].b)return ;
int mid=s[x].a+s[x].b>>;
if(y<=mid)change(x<<,y);
else change(x<<|,y);
}
void get(int x,int y)
{
if(y>s[x].b)return ;
if(y<s[x].a)
{
ans+=s[x].v;
return ;
}
get(x<<,y);
get(x<<|,y);
}
int main()
{
while(scanf("%d",&n))
{
if(!n)break;
ans=;
build(,,);
for(int i=;i<=n;i++)scanf("%d",&x[i].num),x[i].id=i;
sort(x+,x+n+,cmp);
for(int i=;i<=n;i++)a[x[i].id]=i;
for(int i=;i<=n;i++)
{
change(,a[i]);
get(,a[i]);
}
printf("%lld\n",ans);
}
}
被旁边大佬写的树状数组吊锤啊。。呜呜呜!
接下来引进本质不同的逆序对:
Description
Input
N<=10^5。Ai<=10^5
Output
Sample Input
4
3
2
3
2
Sample Output
3
1
本质不同的逆序对就是把数列中的多次出现的数都看做只出现了1次(语文被狗吃了),得到的逆序对个数(就是不同的数组成的逆序对个数),希望大家能看懂。
那么怎么处理呢,这个就要考虑离线了(因为你不能知道这个数什么时候首次出现,什么时候最后出现,这样才能确定能以他作为逆序对的范围)
所以我们需要离线处理出来每个数第一次出现位置,和最后一次出现位置
当某个数首次出现把他加入线段树(单点修改),最后一次出现时求出包含该数的逆序对(query)
全部加起来就是答案了
也就是普通的逆序对改一点点
代码如下:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
void read(int &x) {
char ch; bool ok;
for(ok=,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=;
for(x=; isdigit(ch); x=x*+ch-'',ch=getchar()); if(ok) x=-x;
}
struct oo
{
int a,b,num;
}s[];
int n,m,d[],used[],f[];long long ans,k,sum;
void build(int now,int x,int y)
{
s[now].a=x,s[now].b=y;
s[now].num=;
if(x==y)
return;
else
{
build(now*,x,x+y>>);
build(now*+,(x+y>>)+,y);
s[now].num=s[now<<].num+s[(now<<)+].num;
}
}
void change(int now,int x)
{
s[now].num++;
if(s[now].a==s[now].b)return;
int mid=s[now].a+s[now].b>>;
if(x>mid)change(now*+,x);
else change(now*,x);
}
void get(int now,int x)
{
if(s[now].b<x)return ;
if(s[now].a>x)
ans+=s[now].num;
else
{
if(s[now].a==s[now].b)return ;
int mid=s[now].a+s[now].b>>;
get(now*+,x);
get(now*,x);
}
}
int main()
{
read(n);
for(int i=;i<=n;i++)
{
read(d[i]),m=max(m,d[i]);
if(f[d[i]]==)f[d[i]]=i;
used[d[i]]=i;
}
build(,,m);
for(int i=;i<=n;i++)
{
change(,d[i]);
get(,d[i]);
}
printf("%lld\n",ans);
ans=;
build(,,m);
for(int i=;i<=n;i++)
{
if(f[d[i]]==i)change(,d[i]);
if(used[d[i]]==i)get(,d[i]);
}
printf("%lld",ans);
}
Poj2299 Ultra-QuickSort(另附本质不同逆序对)的更多相关文章
- poj2299树状数组入门,求逆序对
今天入门了树状数组 习题链接 https://blog.csdn.net/liuqiyao_01/article/details/26963913 离散化数据:用一个数组来记录每个值在数列中的排名,不 ...
- Ultra-QuickSort——[归并排序、分治求逆序对]
Description In this problem, you have to analyze a particular sorting algorithm. The algorithm proce ...
- poj2299(归并排序求逆序对)
题目链接:https://vjudge.net/problem/POJ-2299 题意:给定一个序列,每次只能交换邻近的两个元素,问要交换多少次才能使序列按升序排列. 思路:本质就是求逆序对.我们用归 ...
- POJ-2299 Ultra-QuickSort---树状数组求逆序对+离散化
题目链接: https://vjudge.net/problem/POJ-2299 题目大意: 本题要求对于给定的无序数组,求出经过最少多少次相邻元素的交换之后,可以使数组从小到大有序. 两个数(a, ...
- 用归并排序或树状数组求逆序对数量 poj2299
题目链接:https://vjudge.net/problem/POJ-2299 推荐讲解树状数组的博客:https://blog.csdn.net/int64ago/article/details/ ...
- POJ2299逆序对模板(树状数组)
题目:http://poj.org/problem?id=2299 只能相邻两个交换,所以交换一次只会减少一个逆序对.所以交换次数就是逆序对数. ps:原来树状数组还可以记录后边lowbit位的部分和 ...
- poj2299 Ultra-QuickSort(线段树求逆序对)
Description In this problem, you have to analyze a particular sorting algorithm. The algorithm proce ...
- poj2299——逆序对
题目:http://poj.org/problem?id=2299 逆序对,注意树状数组维护后缀和. 代码如下: #include<iostream> #include<cstdio ...
- 逆序对(POJ2299 Ultra-QuickSort)
#include<bits/stdc++.h> using namespace std; int n; ],b[],ans;//a为待排序数组,b为临时数组,ans为逆序对数 void m ...
随机推荐
- socket基本使用
UDP发送和接收 MainRecv.cpp #include <iostream> #include <WinSock2.h> #include <sstream> ...
- stm32 USART使用标志
在USART的发送端有2个寄存器,一个是程序可以看到的USART_DR寄存器,另一个是程序看不到的移位寄存器,对应USART数据发送有两个标志,一个是TXE=发送数据寄存器空,另一个是TC=发送结束. ...
- (转)Java经典设计模式(3):十一种行为型模式(附实例和详解)
原文出处: 小宝鸽 Java经典设计模式共有21中,分为三大类:创建型模式(5种).结构型模式(7种)和行为型模式(11种). 本文主要讲行为型模式,创建型模式和结构型模式可以看博主的另外两篇文章:J ...
- ffmpeg: error while loading shared libraries: libavdevice.so.52
今天在编译安装ffmpeg的时候出现了题目中的问题,最终解决方案如下: errors: ffmpeg正常安装后执行ffmpeg时出现如下错误:ffmpeg: error while loading s ...
- C#开发遇到的常见问题及知识点
今天遇到的类型初始值设定项引发异常的原因是:类没有添加[Serializable]属性. this.DialogResult = System.Windows.Forms.DialogResult.O ...
- git比较两个版本,获取所有代码有差别的文件,并拷贝到一个文件夹中
git diff 3b3855d a024af5 --name-only | xargs -i cp '{}' ./update/ --parents 解释:通过xargs 命令,把git diff ...
- Android-Styles and Themes [From API Guide]
This blog was opened 5 months ago and it has 57 posts now,but the poor thing is by now no one has co ...
- 「LOJ#103」子串查找 (Hash
题目描述 这是一道模板题. 给定一个字符串 A A A 和一个字符串 B B B,求 B B B 在 A A A 中的出现次数.AAA 和 BBB 中的字符均为英语大写字母或小写字母. A A A 中 ...
- webpack安装后package-lock.json 的作用
这个文件主要功能是确定当前安装的包的依赖,以便后续重新安装的时候生成相同的依赖,而忽略项目开发过程中有些依赖已经发生的更新. 避免了依赖升级和当前项目不兼容!
- node process-进程
process对象是一个全局变量,提供Node.js进程的有关信息以及控制进程.因为是全局变量所以可以直接使用