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 ...
随机推荐
- SE14 调整并激活数据库
一.使用SE14 激活并调整MARA 时的消息:(体验心惊肉跳,你就改改标准表试试.-增强也请小心谨慎) 使用检查: 调整并激活后的结果: 二.如果 运行时对象检查 出错误,参考 http://blo ...
- spring IOC(转)
原文 http://stamen.iteye.com/blog/1489223 引述:IoC(控制反转:Inverse of Control)是Spring容器的内核,AOP.声明式事务等功能在此基础 ...
- PPTP&L2TP&PPPOE client and server configure
一. PPPOE 1. server(参考http://laibulai.iteye.com/blog/1171898) (1)安装rp-pppoe:yum install rp-pppoe (2)配 ...
- Anroid事件分发
因为最近因个人原因离职,面试的时候,有人问到了Android中事件分发机制的过程,因为忘得差不多了,没答好,所以回来后,想写了个Demo,重新复习一遍. 一般来说,Android的组件其实可以分为两类 ...
- ubuntu12.04不能记住上次编辑位置的解决方案
1:按照网上的代码 au BufReadPost * |if line("'\"") <= line("$")|exe("norm ' ...
- C++打印变量地址
%p专门用来打印变量的以十六进制表示的地址: #include<iostream> using namespace std; int main() { ; printf("a的地 ...
- laravel基础课程---2、Laravel配置文件、路由及php artisan(php artisan是什么)
laravel基础课程---2.Laravel配置文件.路由及php artisan(php artisan是什么) 一.总结 一句话总结: PHP工具匠:php artisan,其实本身就是一些PH ...
- EnumDescription
using System; using System.Reflection; using System.Collections; using System.Collections.Generic; n ...
- Java标准输入
Java: import java.util.*; public class Main{ public static void main(String args[]){ Scanner cin = n ...
- html锚点实现的方法
1 通过id <a href="#div1"> 通过id获取锚点</a> <div style=" height:200px; width: ...