1. 程式人生 > >模板——權值線段樹(逆序對)

模板——權值線段樹(逆序對)

code logs d+ produce inpu body click end sequence

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

Waterloo local 2005.02.05 大意就是給若幹個長度為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 }
神奇的代碼

模板——權值線段樹(逆序對)