poj 2299 Ultra-QuickSort 【线段树 or 线段树+lazy or 树状数组 or 归并排序】 求逆序对

Ultra-QuickSort
Time Limit: 7000MS   Memory Limit: 65536K
Total Submissions: 46504   Accepted: 16945

Description

poj 2299 Ultra-QuickSort 【线段树 or 线段树+lazy or 树状数组 or 归并排序】 求逆序对_第1张图片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
求逆序数思路:首先初始化所有节点对应区间为0,然后优先插入最大值,并把最大值所在位置赋值为1,再查询插入位置前有多少个数(就是求1到 当前插入位置-1 之和),每次累加即是所有逆序对。
线段树(不用lazy思想)766ms:
 
  
#include 
#include 
#include 
#define MAX 500000+10
#define LL long long
using namespace std;
int sum[MAX<<2];
struct record
{
    int val, pos;
}num[MAX];
bool cmp(record a,record b)
{
    return a.val > b.val;
} 
void build(int o, int l, int r)//建树 
{
    sum[o] = 0;
    if(l == r)
    return ; 
    int mid = (l+r) >> 1;
    build(o<<1, l, mid);
    build(o<<1|1, mid+1, r);
}
int query(int o, int l, int r, int L, int R)//查询 
{
    if(L == l && R == r)
    {
        return sum[o]; 
    }
    int mid = (l+r) >> 1;
    if(R <= mid)  return query(o<<1, l, mid, L, R);
    else if(L > mid)  return query(o<<1|1, mid+1, r, L, R);
    else  return query(o<<1, l, mid, L, mid) + query(o<<1|1, mid+1, r, mid+1, R);
}
void update(int o, int l, int r, int L)//更新 
{
    sum[o] += 1;
    if(l == r) return ;
    int mid = (l+r) >> 1;
    if(L <= mid) update(o<<1, l, mid, L);
    else update(o<<1|1, mid+1, r, L); 
}
int main()
{
    int n, i;
    LL ans;
    while(scanf("%d", &n), n)
    {
        build(1, 1 ,n);
        for(i = 0; i < n; i++)
        {
            scanf("%d", &num[i].val);
            num[i].pos = i + 1;
        }
        sort(num, num+n, cmp);
        ans = 0;
        for(i = 0; i < n; i++)
        {
            update(1, 1, n, num[i].pos);
            if(num[i].pos == 1)
            continue;
            ans += query(1, 1, n, 1, num[i].pos-1);
        }
        printf("%lld\n", ans);
    }
    return 0;
}


线段树+lazy 938ms:
 
  
#include 
#include 
#include 
#define MAX 500000+10
#define LL long long
using namespace std;
int sum[MAX<<2];
struct record
{
    int val, pos;
}num[MAX];
bool cmp(record a,record b)
{
    return a.val > b.val;
} 
void PushUp(int o)
{
    sum[o] = sum[o<<1] + sum[o<<1|1];
}
void build(int o, int l, int r)//建树 
{
    sum[o] = 0;
    if(l == r)
    return ; 
    int mid = (l+r) >> 1;
    build(o<<1, l, mid);
    build(o<<1|1, mid+1, r);
    PushUp(o);
}
int query(int o, int l, int r, int L, int R)//查询 
{
    if(L <= l && R >= r)
    {
        return sum[o]; 
    }
    int mid = (l+r) >> 1;
    int res = 0;
    if(L <= mid) res += query(o<<1, l, mid, L, R);
    if(R > mid) res += query(o<<1|1, mid+1, r, L, R);
    return res;
}
void update(int o, int l, int r, int L)//更新 
{
    if(l == r)
    {
        sum[o] += 1;
        return ;
    } 
    int mid = (l+r) >> 1;
    if(L <= mid) update(o<<1, l, mid, L);
    else update(o<<1|1, mid+1, r, L); 
    PushUp(o);
}
int main()
{
    int n, i;
    LL ans;
    while(scanf("%d", &n), n)
    {
        build(1, 1 ,n);
        for(i = 0; i < n; i++)
        {
            scanf("%d", &num[i].val);
            num[i].pos = i + 1;
        }
        sort(num, num+n, cmp);
        ans = 0;
        for(i = 0; i < n; i++)
        {
            update(1, 1, n, num[i].pos);
            if(num[i].pos == 1)
            continue;
            ans += query(1, 1, n, 1, num[i].pos-1);
        }
        printf("%lld\n", ans);
    }
    return 0;
}

树状数组 500ms:
 
  
#include 
#include 
#include 
#define MAX 500000
#define LL long long 
using namespace std;
int c[MAX];
int n;
struct record
{
    int val, pos;//记录数值 和 位置 
}num[MAX];
bool cmp(record a,record b)
{
    return a.val > b.val;
}
int lowbit(int x)
{
    return x&(-x);
}
int sum(int x)
{
    int s = 0;
    while(x > 0)
    {
        s += c[x];
        x -= lowbit(x);
    }
    return s;
}
void update(int x)
{
    while(x <= n)
    {
        c[x] += 1;
        x += lowbit(x); 
    }
}
int main()
{
    int i, j;
    LL ans;
    while(scanf("%d", &n), n)
    {
        memset(c, 0, sizeof(c));
        for(i = 0;i < n; i++)
        {
            scanf("%d", &num[i].val);
            num[i].pos = i + 1;
        }
        sort(num, num+n, cmp);
        ans = 0;
        for(i = 0;i < n; ++i)//每一次插入当前最大值 
        {
            update(num[i].pos);
            ans += sum(num[i].pos-1);//统计前面有多少个数 
        }
        printf("%lld\n", ans);
    }
    return 0;
}

归并排序:391ms
 
  
#include 
#include 
#define MAX 500000+10
#define LL long long
using namespace std;
int a[MAX], tmp[MAX];
LL ans;
void Merge(int l, int m, int r)
{
    int i = l;
    int j = m + 1;
    int k = l;
    while(i <= m && j <= r)
    {
        if(a[i] > a[j])
        {
            tmp[k++] = a[j++];
            ans += m - i + 1;
        }
        else
        {
            tmp[k++] = a[i++];
        }
    }
    while(i <= m) tmp[k++] = a[i++];
    while(j <= r) tmp[k++] = a[j++];
    for(int i = l; i <= r; i++)
    {
        a[i] = tmp[i];
    }
}
void Merge_sort(int l,int r)
{
    if(l < r)
    {
        int m = (l + r) >> 1;
        Merge_sort(l,m);
        Merge_sort(m+1,r);
        Merge(l,m,r);
    }
}
int main()
{
    int n;
    int i, j;
    while(scanf("%d", &n),n)
    {
        for(i = 0; i < n; i++)
        {
            scanf("%d", &a[i]);
        }
        ans = 0;
        Merge_sort(0,n-1);
        printf("%lld\n", ans);
    }
    return 0;
}

你可能感兴趣的:(线段树,树状数组,逆序对)