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
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.
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; }