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 ...
随机推荐
- 15款创建美丽幻灯片的 jQuery 插件
1. Skippr Skippr 是一个超级简单的 jQuery 幻灯片插件.仅仅是包含你的网页中引入 jquery.skippr.css 和 jquery.skippr.js 文件就能使用了. Sk ...
- Javascript的参数详解
函数可以有参数也可以没有参数,如果定义了参数,在调用函数的时候没有传值,默认设置为undefined 在调用函数时如果传递参数超过了定义时参数,jS会忽略掉多余参数 jS中不能直接写默认值,可以通过a ...
- 建立FTP服务器(FTP服务器名要与创建的用户名一致)
1新建用户 2. 3.建立FTP
- Machine Learning in Action(2) 决策树算法
决策树也是有监督机器学习方法. 电影<无耻混蛋>里有一幕游戏,在德军小酒馆里有几个人在玩20问题游戏,游戏规则是一个设迷者在纸牌中抽出一个目标(可以是人,也可以是物),而猜谜者可以提问题, ...
- Parallel Tests
Parallel Tests Parallel Android Tests Appium provides a way for users to automate multiple Android s ...
- observer远程监控服务器
因为需要监控服务器的状况,所以要使用工具observer.但是observer是采用wxWidget开发的,远程机器没有此环境.于是在windows机器上装了虚拟机ubuntu,又折腾erlang和w ...
- Material Design 之 定义状态栏(Status Bar)的颜色
Hey,好久不见.今天遇到一个问题,想要把Status Bar 和 Tool Bar的颜色弄成一样的,或者是类似的,例如Material Design: 图中Status Bar颜色比Tool Bar ...
- 【CQ18高一暑假前挑战赛3.5】标程
[A:快速幂相关] #include<bits/stdc++.h> using namespace std; int qpow(int a,int x){ a%=;; while(x){ ...
- YouTube视频签名加密算法的破解
密码学方法 多年以前,YouTube的视频源地址是直接encode在页面中的,你甚至可以用一行Perl来下载它们. 直到2012年8月,这个简单的脚本(用在0.0.1版本的You-Get中)仍然可以解 ...
- swprintf has been changed to conform with the ISO C standard, adding an extra character count parameter.
'swprintf': swprintf has been changed to conform with the ISO C standard, adding an extra character ...