POJ 2299-Ultra-QuickSort-线段树的两种建树方式
此题有两种建树方式!
Description
In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swapping two adjacent sequence elements until the sequence is sorted in ascending order.
For the input sequence
9 1 0 5 4 ,
Ultra-QuickSort produces the output
0 1 4 5 9 .
Your task is to determine how many swap operations Ultra-QuickSort needs to perform in order to sort a given input sequence.
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
题目大意:
给定一个排列,求这个排列的逆序数。
逆序的定义
在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。
核心思想:
我们用结构体来存储排列:

a[i].x表示第i个数的数值,a[i].id表示第i个数的位置。
对于每一个数a[i].x,我们找到位置在它前面并且数值比它大的数的个数c[i],c数组的和就是答案。
线段树。
我们在统计个数的时候,数要满足两个条件:
1、位置在它前面
2、数值比它大
我们在空间和时间上分别加以控制来满足这两个条件。
空间:线段树的左右区间。
时间:线段树的更新顺序。
所以此题有两种建树方式,
方式一
从空间上加以控制来满足位置在它前面的条件;
从时间上加以控制来满足数值比它大的条件。
线段树的左右区间表示原排列中数的位置,通过控制查询时左右区间的端点来满足位置在它前面的条件。
我们将a数组按x降序排列,按照新的顺序依次更新线段树,数值的大的先进入(更新)线段树,所以现在从线段树上查询到的个数一定满足数值比它大的条件。
此方式建树不需要离散化,下面的方式需要离散化。
方式二
从空间上加以控制来满足数值比它大的条件;
从时间上加以控制来满足位置在它前面的条件。
线段树的左右区间表示原排列中数的数值,通过控制查询时左右区间的端点来满足数值比它大的条件。
我们将a数组按id升序排列(也就是原顺序),位置靠前的先进入(更新)线段树,所以现在从线段树上查询到的个数一定满足位置在它前面的条件。
注意:此题目数的数值范围是1e10,将数值作为线段树区间长度开不出这么大的数组。解决方法是离散化。

离散前后的映射函数是:

离散后的数值范围是不同数值的个数,也就是5e5。这样就可以开数组建树了。
方式一代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=5e5+20;
char s[20];
//存原排列
struct node{
int x,id;
}a[N];
struct tnode{
int l,r,sum;
}tr[N<<2];
void pushup(int m)
{
tr[m].sum=tr[m<<1].sum+tr[m<<1|1].sum;
return;
}
void build(int m,int l,int r)
{
tr[m].l=l;
tr[m].r=r;
if(l==r)
{
tr[m].sum=0;
return;
}
int mid=(l+r)>>1;
build(m<<1,l,mid);
build(m<<1|1,mid+1,r);
pushup(m);
return;
}
void update(int m,int x)
{
if(tr[m].l==x&&tr[m].r==x)
{
tr[m].sum=1;
return;
}
int mid=(tr[m].l+tr[m].r)>>1;
if(x<=mid)
update(m<<1,x);
else
update(m<<1|1,x);
pushup(m);
return;
}
int query(int m,int l,int r)
{
if(tr[m].l==l&&tr[m].r==r)
return tr[m].sum;
int mid=(tr[m].l+tr[m].r)>>1;
if(r<=mid)
return query(m<<1,l,r);
if(l>mid)
return query(m<<1|1,l,r);
return query(m<<1,l,mid)+query(m<<1|1,mid+1,r);
}
bool cmp(node p,node q)
{
return p.x>q.x;
}
int main()
{
int n;
while(1)
{
scanf("%d",&n);
if(!n)
break;
//根据n直接建树
build(1,1,n);
//输入
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i].x);
a[i].id=i;
}
//排序,x大的先进入线段树
sort(a+1,a+n+1,cmp);
//边更新边查询
ll ans=0;
for(int i=1;i<=n;i++)
{
ans+=query(1,1,a[i].id);
update(1,a[i].id);
}
//输出
printf("%lld\n",ans);
}
return 0;
}
方式二代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=5e5+20;
int b[N],cnt;
//存原排列
struct node{
int x,id;
}a[N];
struct tnode{
int l,r,sum;
}tr[N<<2];
void pushup(int m)
{
tr[m].sum=tr[m<<1].sum+tr[m<<1|1].sum;
return;
}
void build(int m,int l,int r)
{
tr[m].l=l;
tr[m].r=r;
if(l==r)
{
tr[m].sum=0;
return;
}
int mid=(l+r)>>1;
build(m<<1,l,mid);
build(m<<1|1,mid+1,r);
pushup(m);
return;
}
void update(int m,int x)
{
if(tr[m].l==x&&tr[m].r==x)
{
tr[m].sum=1;
return;
}
int mid=(tr[m].l+tr[m].r)>>1;
if(x<=mid)
update(m<<1,x);
else
update(m<<1|1,x);
pushup(m);
return;
}
int query(int m,int l,int r)
{
if(tr[m].l==l&&tr[m].r==r)
return tr[m].sum;
int mid=(tr[m].l+tr[m].r)>>1;
if(r<=mid)
return query(m<<1,l,r);
if(l>mid)
return query(m<<1|1,l,r);
return query(m<<1,l,mid)+query(m<<1|1,mid+1,r);
}
bool cmp1(node p,node q)
{
return p.x<q.x;
}
bool cmp2(node p,node q)
{
return p.id<q.id;
}
int getid(int x)
{
return lower_bound(b,b+cnt,x)-b+1;
}
int main()
{
int n;
while(1)
{
scanf("%d",&n);
if(!n)
break;
//输入
a[0].x=-1;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i].x);
a[i].id=i;
}
//先离散化
sort(a+1,a+n+1,cmp1);
cnt=0;
for(int i=1;i<=n;i++)
if(a[i].x!=a[i-1].x)
b[cnt++]=a[i].x;
//根据离散后的cnt建树
build(1,1,cnt);
//别忘了把a数组sort回来
sort(a+1,a+n+1,cmp2);
//边更新边查询
ll ans=0;
for(int i=1;i<=n;i++)
{
int t=getid(a[i].x);
ans+=query(1,t,n);
update(1,t);
}
//输出
printf("%lld\n",ans);
}
return 0;
}
POJ 2299-Ultra-QuickSort-线段树的两种建树方式的更多相关文章
- 线段树:HDU2795-Billboard(建树方式比较新奇)
Billboard Time Limit: 20000/8000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Su ...
- POJ 3225 线段树区间更新(两种更新方式)
http://blog.csdn.net/niuox/article/details/9664487 这道题明显是线段树,根据题意可以知道: (用0和1表示是否包含区间,-1表示该区间内既有包含又有不 ...
- CodeForces Round #179 (295A) - Greg and Array 一个线段树做两次用
线段树的区间更新与区间求和...一颗这样的线段树用两次... 先扫描1~k...用线段树统计出每个操作执行的次数... 那么每个操作就变成了 op. l , op.r , op.c= times* ...
- poj 3667 Hotel (线段树的合并操作)
Hotel The cows are journeying north to Thunder Bay in Canada to gain cultural enrichment and enjoy a ...
- 巨蟒python全栈开发数据库前端6:事件onclick的两种绑定方式&&onblur和onfocus事件&&window.onload解释&&小米商城讲解
1.回顾上节内容(JavaScript) 一.JavaScript概述 1.ECMAScript和JavaScript的关系 2.ECMAScript的历史 3.JavaScript是一门前后端都可以 ...
- Web APi之认证(Authentication)两种实现方式【二】(十三)
前言 上一节我们详细讲解了认证及其基本信息,这一节我们通过两种不同方式来实现认证,并且分析如何合理的利用这两种方式,文中涉及到的基础知识,请参看上一篇文中,就不再叙述废话. 序言 对于所谓的认证说到底 ...
- Android中BroadcastReceiver的两种注册方式(静态和动态)详解
今天我们一起来探讨下安卓中BroadcastReceiver组件以及详细分析下它的两种注册方式. BroadcastReceiver也就是"广播接收者"的意思,顾名思义,它就是用来 ...
- Android中Fragment与Activity之间的交互(两种实现方式)
(未给Fragment的布局设置BackGound) 之前关于Android中Fragment的概念以及创建方式,我专门写了一篇博文<Android中Fragment的两种创建方式>,就如 ...
- JavaScript 函数的两种声明方式
1.函数声明的方式 JavaScript声明函数有两种选择:函数声明法,表达式定义法. 函数声明法 function sum (num1 ,num2){ return num1+num2 } 表达式定 ...
随机推荐
- P1095 守望者的逃离——DP?贪心?
https://www.luogu.org/problem/P1095 恶魔猎手尤迪安野心勃勃,他背叛了暗夜精灵,率领深藏在海底的娜迦族企图叛变.守望者在与尤迪安的交锋中遭遇了围杀,被困在一个荒芜的大 ...
- Python操作Jira
目录 认证 项目(Project) 问题(Issue) 配置域(Fields) 关注者/评论/附件 创建/分配/转换问题 搜索 Jira提供了完善的RESTful API,如果不想直接请求API接口可 ...
- Mac 10.14.5系统偏好设置安全性与隐私不展示任何来源解决办法
Mac新系统升级(10.14.5)后未从appstore下载的软件在安装时会提示安装包已损坏之类的东东,这是因为没有打开“设置”—“安全与隐私”中的“任何来源”造成的,可是升级后的10.14.5却没有 ...
- [bzoj 4887] [Tjoi2017]可乐
传送门 Description 加里敦星球的人们特别喜欢喝可乐.因而,他们的敌对星球研发出了一个可乐机器人,并且 放在了加里敦星球的1号城市上.这个可乐机器人有三种行为:停在原地,去下一个相邻的 城市 ...
- 如何判断Linux下 网卡是虚拟还是物理网卡?
ifconfig命令可以查看Linux系统中正在使用的网卡,包括物理网卡和虚拟网卡,如果想要查看Linux系统中全部的网卡,可以查看/proc/net/dev文件,那如何区分网卡是虚拟还是物理的呢? ...
- Mixed Content: The page at ‘https://XXX’ was loaded over HTTPS, but requested an insecure........
iframe引入视频的文件的时候报这个错 其实只要改成 加上一个s就好了 ...
- 【2018.07.28】(字符串/回文串)学习Manacher算法小记
主要是应用在回文串啦,原理也理解了老半天,如果没有图片的话,我也看不太懂它的原理 学习的灵感来源来自于:https://segmentfault.com/a/1190000008484167 /* 最 ...
- scp执行报错WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
linux环境执行scp时会遇到报错WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!,如下 [root@subsname home]# scp AAA. ...
- RK3288 st7703 mipi屏指令过长,程序跑飞
本文为博主原创文章,转载请注明出处:https://www.cnblogs.com/lialong1st/p/11218433.html CPU:RK3288 系统:Android 5.1 调试 mi ...
- legend3---阿里云服务器配置多个网站项目
legend3---阿里云服务器配置多个网站项目 一.总结 一句话总结: 就是和本机上面的一样,多个域名可以指向同一个ip,配置apache的时候记得ServerName配置域名,不要直接整ip 二. ...