Description

给定一个长度为 n(n≤5*10^5) 的序列 a,如果只允许进行比较和交换相邻两个数的操作
求至少需要多少次交换才能把 a 从小到大排序。

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

线段树大法好!

我一个不会离散化的蒟蒻在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

给定一个序列a1,a2,…,an,如果存在iaj,那么我们称之为逆序对,求逆序对的数目 

Input

第一行为n,表示序列长度,接下来的n行,第i+1行表示序列中的第i个数。 
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(另附本质不同逆序对)的更多相关文章

  1. poj2299树状数组入门,求逆序对

    今天入门了树状数组 习题链接 https://blog.csdn.net/liuqiyao_01/article/details/26963913 离散化数据:用一个数组来记录每个值在数列中的排名,不 ...

  2. Ultra-QuickSort——[归并排序、分治求逆序对]

    Description In this problem, you have to analyze a particular sorting algorithm. The algorithm proce ...

  3. poj2299(归并排序求逆序对)

    题目链接:https://vjudge.net/problem/POJ-2299 题意:给定一个序列,每次只能交换邻近的两个元素,问要交换多少次才能使序列按升序排列. 思路:本质就是求逆序对.我们用归 ...

  4. POJ-2299 Ultra-QuickSort---树状数组求逆序对+离散化

    题目链接: https://vjudge.net/problem/POJ-2299 题目大意: 本题要求对于给定的无序数组,求出经过最少多少次相邻元素的交换之后,可以使数组从小到大有序. 两个数(a, ...

  5. 用归并排序或树状数组求逆序对数量 poj2299

    题目链接:https://vjudge.net/problem/POJ-2299 推荐讲解树状数组的博客:https://blog.csdn.net/int64ago/article/details/ ...

  6. POJ2299逆序对模板(树状数组)

    题目:http://poj.org/problem?id=2299 只能相邻两个交换,所以交换一次只会减少一个逆序对.所以交换次数就是逆序对数. ps:原来树状数组还可以记录后边lowbit位的部分和 ...

  7. poj2299 Ultra-QuickSort(线段树求逆序对)

    Description In this problem, you have to analyze a particular sorting algorithm. The algorithm proce ...

  8. poj2299——逆序对

    题目:http://poj.org/problem?id=2299 逆序对,注意树状数组维护后缀和. 代码如下: #include<iostream> #include<cstdio ...

  9. 逆序对(POJ2299 Ultra-QuickSort)

    #include<bits/stdc++.h> using namespace std; int n; ],b[],ans;//a为待排序数组,b为临时数组,ans为逆序对数 void m ...

随机推荐

  1. Java面试-Hibernate总结

    1  Hibernate的检索方式 Ø  导航对象图检索(依据已经载入的对象.导航到其它对象. ) Ø  OID检索(依照对象的OID来检索对象. ) Ø  HQL检索(使用面向对象的HQL查询语言. ...

  2. 6 Maven聚合与集成

    Maven的聚合特性能够把项目的各个模块聚合在一起构件,而Maven的继承特性能够帮助抽取各个模块相同的依赖和插件等配置,简化POM的同时,还能促进各个模块配置的一致性.     1.聚合     为 ...

  3. SE14 调整并激活数据库

    一.使用SE14 激活并调整MARA 时的消息:(体验心惊肉跳,你就改改标准表试试.-增强也请小心谨慎) 使用检查: 调整并激活后的结果: 二.如果 运行时对象检查 出错误,参考 http://blo ...

  4. Perl 正则表达式语法

    1. 概要 Perl正则表达式是Boost.regex 默认行为,也可以将perl传入basic_regex 构造. boost::regex  e1(my_expression); boost::r ...

  5. [noip2014day1-T3]飞扬的小鸟

    Flappy Bird 是一款风靡一时的休闲手机游戏.玩家需要不断控制点击手机屏幕的频率来调节小鸟的飞行高度,让小鸟顺利通过画面右方的管道缝隙.如果小鸟一不小心撞到了水管或者掉在地上的话,便宣告失败. ...

  6. Gym - 100283F F. Bakkar In The Army —— 二分

    题目链接:http://codeforces.com/gym/100283/problem/F F. Bakkar In The Army time limit per test 2 seconds ...

  7. MYSQL进阶学习笔记十八:MySQL备份和还原!(视频序号:进阶_37)

    知识点十九:MySQL的备份的还原(38) 一.mysql的备份 1.通过使用mysqldump的命令备份 使用mysqldump命令备份,mysqldump命令将数据库中的数据备份成一个文本文件.表 ...

  8. 使用libcurl进行HTTP GET操作

    Working example how to do a GET request with libcurl and save it to a string variable for future use ...

  9. BZOJ 1632 [Usaco2007 Feb]Lilypad Pond:spfa【同时更新:经过边的数量最小】【路径数量】

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1632 题意: 有一个n*m的池塘.0代表水,1代表荷花,2代表岩石,3代表起点,4代表终点 ...

  10. Git 常用命令学习

    本文转载自:https://buptldy.github.io/2016/03/02/2016-03-02-Git%20Cheat%20Sheet/ 文章 创建版本库 初始化一个Git仓库,使用git ...