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 ...
随机推荐
- eclipse的maven、Scala环境搭建
最近重新搭建了一下maven+Scala的环境,发现很多东西都不记得了,于是重新记录一遍. 嫌搭建麻烦的话也可以直接下载Scala官方做好的环境http://scala-ide.org/downloa ...
- windows与mac共享文件
实际操作环境是win10实体机与mac10.10虚拟机共享文件. 需要两步操作: 在win10中设置一个共享文件夹: 在mac中点击Finder——窗口左侧的列表——共享的——共享屏幕——输入用户名密 ...
- Hadoop安全
kerberos-hadoop配置常见问题汇总 注意事项 常见问题如下(其中前面两点最多): 各目录属主组属性修改. 对于hadoop,需要改为yarn:hadoop/mapred:hdoop/hdf ...
- matlab从fig文件中提取数据
如果你的fig文件中图像是由多条曲线绘制而成,比如说plot命令生成的,通过以下方式输出横坐标,纵坐标的取值 open('figname.fig'); lh = findall(gca, 'type' ...
- python字典无序?有序?
默认情况下Python的字典输出顺序是按照键的创建顺序. 字典的无序是指,不能人为重新排序.比如说你按键值1,2,3,4的顺序创建的字典,只能由解析器按创建顺序,还是1,2,3,4的输出.你无法控制它 ...
- ora-12519:TNS ,no appropriate service handler found
今天有同事反应,数据库连不了,提示 ora-12519:TNS ,no appropriate service handler found: 一开始以为监听没有启动,排查后,发现正常:于是google ...
- PHP 中$_SERVER的用法
php编程中经常需要用到一些服务器的一些资料,我把常用的用高亮的方式贴出来,其余的放在后面.方便以后查阅$_SERVER['HTTP_ACCEPT_LANGUAGE']//浏览器语言 $_SERVER ...
- HDU3157 Crazy Circuits
传送门 有源汇的上下界网络流求最小流. 这个其实和上道题差不多--题目描述我没怎么看明白--好像就是让你按照他说的把图建出来就行了,注意这个题的字符处理,可能有长度大于1的字符串,要注意一下.求最小流 ...
- react之redux增加删除数字
比如在页面中添加和删除‘222’ action.js export const ADD= 'ADD'; export const RED='RED'; export const add=(str)=& ...
- IntelliJ IDEA 2018 设置代码提示对大小写不敏感
setting->Editor->General->Code Completion取消勾选Match case