模板——权值线段树(逆序对)

Posted ~Lanly~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了模板——权值线段树(逆序对)相关的知识,希望对你有一定的参考价值。

Ultra-QuickSort
Time Limit: 7000MS   Memory Limit: 65536K
Total Submissions: 62455   Accepted: 23259

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

Source

 
大意就是给若干个长度为n的序列求逆序对个数。
权值线段树维护的是某个值出现的次数,所以一开始是空树(换句话说就不用建树了2333),然后不断按顺序从左到右插入点,很显然每插入一个点就记录比这个点大的个数即为此时的逆序对个数,然后累计即可。
因为数值可达9亿9千9百9十9万9千9百9十9,但个数最多只有500000,所以先离散后插入。(ans要long long!!!)
 
技术分享
 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<algorithm>
 5 using namespace std;
 6 int n,a[500005],tmp[500005],size;
 7 long long ans,cnt[2000005];
 8 void init(int root,int l,int r,int x){
 9     if ((l==r)&&(l==x)) {
10         cnt[root]++;
11         return;
12     }
13     int mid=(l+r)>>1;
14     if (x<=mid) init(root<<1,l,mid,x);
15     else if (x>mid) init(root<<1|1,mid+1,r,x);
16     cnt[root]=cnt[root<<1]+cnt[root<<1|1];
17 }
18 long long sum(int root,int l,int r,int x,int y){
19     if ((x<=l)&&(y>=r)) return cnt[root];
20     long long anss=0;
21     int mid=(l+r)>>1;
22     if (x<=mid) anss+=sum(root<<1,l,mid,x,y);
23     if (y>mid) anss+=sum(root<<1|1,mid+1,r,x,y);
24     return anss;
25 }
26 int main(){
27     scanf("%d",&n);
28     while (n){
29         memset(a,0,sizeof(a));
30         memset(cnt,0,sizeof(cnt));
31         memset(tmp,0,sizeof(tmp));
32         size=0;
33         ans=0;
34         for (int i=1;i<=n;i++){
35          scanf("%d",&a[i]);
36          tmp[i]=a[i];
37         }
38         sort(tmp+1,tmp+1+n);
39         size=unique(tmp+1,tmp+1+n)-(tmp+1);
40         for (int i=1;i<=n;i++)
41          a[i]=lower_bound(tmp+1,tmp+1+size,a[i])-(tmp+1)+1;
42         for (int i=1;i<=n;i++){
43          init(1,1,n,a[i]);
44          ans+=sum(1,1,n,a[i]+1,n);
45         }
46         printf("%lld\n",ans);
47         scanf("%d",&n);
48     }
49     return 0;
50 }
神奇的代码

 

 

以上是关于模板——权值线段树(逆序对)的主要内容,如果未能解决你的问题,请参考以下文章

权值线段树求逆序对问题

Codevs 1688 求逆序对(权值线段树)

权值线段树离散化介绍 (+利用 线段树 求逆序对)

[POI2011]ROT-Tree Rotations 线段树合并|主席树 / 逆序对

HDU1394(权值线段树)

HDU - 5592 ZYB's Premutation (权值线段树)