poj 2299 , 线段树
Ultra-QuickSort
| Time Limit: 7000MS | Memory Limit: 65536K | |
| Total Submissions: 35702 | Accepted: 12856 |
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 Ultra-QuickSort produces the output
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
Source
归并排序,线段树都可以,这是线段树版本,参考了网上题解,另外抄下我看懂了的解答
(来自 :http://zhidao.baidu.com/link?url=aqpEDgNFTQkoM4X9ebJMV-DpXoJvE5L8p9P3S-ysVJpUX_qBNdG99pHU00pOodYtMlNDKBiSkiIwc61ROroHbq )
“很简单……
设数列为a,将数列离散化,在从前往后枚举,统计答案……
离散化:例如2 5 8 3 10 等价于 1 3 4 2 5,可以通过排序加小小处理解决。
枚举到第i个数,我们需要求出从1到i-1中有多少个比a[i]大的数,更新答案。
具体怎么做呢?
每次枚举完一个数之后,将这个数插入到线段树里,插入到线段树的神马地方呢?当然是这个数多大就插入到多大的地方。
举个例子:3 2 4 1。则线段树的变化应该为:tree[3]+=1;tree[2]+=1;tree[4]+=1;tree[1]+=1;
设x=a[i],这样,在插入一个数X时,首先求一下tree[x+1]~tree[n]的和,这个和就是1~i-1中有多少个比a[i]大的数。运用线段树求和可以做到O(n log n)吧,具体实现我就不再赘述了。”
设数列为a,将数列离散化,在从前往后枚举,统计答案……
离散化:例如2 5 8 3 10 等价于 1 3 4 2 5,可以通过排序加小小处理解决。
枚举到第i个数,我们需要求出从1到i-1中有多少个比a[i]大的数,更新答案。
具体怎么做呢?
每次枚举完一个数之后,将这个数插入到线段树里,插入到线段树的神马地方呢?当然是这个数多大就插入到多大的地方。
举个例子:3 2 4 1。则线段树的变化应该为:tree[3]+=1;tree[2]+=1;tree[4]+=1;tree[1]+=1;
设x=a[i],这样,在插入一个数X时,首先求一下tree[x+1]~tree[n]的和,这个和就是1~i-1中有多少个比a[i]大的数。运用线段树求和可以做到O(n log n)吧,具体实现我就不再赘述了。”
我的AC代码(用map会TLE。。。):
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>
#include<queue>
#include<string>
#include<cmath>
#include<fstream>
#include<iomanip>
#include<map>
using namespace std;
#define LL long long
#define MAXN 500005
#define lson rt<<1, l, m
#define rson rt<<1|1, m, r
int n, sum[MAXN<<2];
int query(int rt, int l, int r, int cl, int cr){
if(cl<=l && cr>=r) return sum[rt];
int ret = 0;
int m = l + r >> 1;
if(cl < m) ret += query(lson, cl, cr);
if(cr > m) ret += query(rson, cl, cr);
return ret;
}
void update(int rt, int l, int r, int x){
if(l+1 == r){
sum[rt]++; return;
}
int m = l + r >> 1;
if(x < m) update(lson, x);
else update(rson, x);
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
struct node{
int val, id;
bool operator <(const node &rhs)const{
return val < rhs.val;
}
}t[MAXN];
int rank[MAXN];
int main(){
// freopen("C:\\Users\\Administrator\\Desktop\\in.txt","r",stdin);
while(scanf(" %d", &n)==1 && n){
for(int i=0; i<n; i++)
scanf(" %d", &t[i].val), t[i].id=i;
sort(t, t+n);
fill_n(sum+1, n<<2, 0);
for(int i=0; i<n; i++) rank[t[i].id]=i+1;
LL ans = 0;
for(int i=0; i<n; i++){
int t = rank[i];
ans += query(1, 1, 1+n, t, 1+n);
update(1, 1, 1+n, t);
}
printf("%lld\n", ans);
}
return 0;
}
归并排序
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 500005;
int a[maxn], sub[maxn];
long long cnt;
void merg(int *a, int n){
int *b= a + (n>>1), n1 = n>>1, n2 = n-n1;
for(int i=0, j=0, k=0; i<n1 || j<n2; ){
if(i<n1 && j<n2){
if(a[i]>b[j]) sub[k++] = b[j++], cnt += n1-i;
else sub[k++] = a[i++];
}
else if(i<n1) sub[k++] = a[i++];
else sub[k++] = b[j++];
}
memcpy(a, sub, n*sizeof(int));
}
void mergesort(int *a, int n){
if(n<2) return;
mergesort(a, n>>1);
mergesort(a+(n>>1), n-(n>>1));
merg(a, n);
}
int main(){
int n;
while(scanf(" %d", &n)==1 && n){
for(int i=0; i<n; i++) scanf(" %d", a+i);
cnt = 0;
mergesort(a, n);
printf("%lld\n", cnt);
}
return 0;
}

浙公网安备 33010602011771号