训练日记-16

来源:互联网 发布:做淘宝电脑配置 编辑:程序博客网 时间:2024/06/11 05:57

        今天首先把树状数组中求逆序数的算法看了一下,然后看了一下线段树的课件。

       逆序数的基本框架如下:

#include <iostream>

#include <stdio.h>

#include <cmath>

#include <algorithm>

#include <cstring>

using namespace std;

 

int b[500005], c[500005];

int n;

 

struct node

{

    int num, id;

}a[500005];

 

bool cmp(node a, node b)

{

    return a.num < b.num;

}

 

void update(int i, int x)

{

    while(i <= n)

    {

        c[i] += x;

        i += i&(-i);

    }

}

 

int sum(int i)

{

    int sum = 0;

    while(i > 0)

    {

        sum += c[i];

        i -= i&(-i);

    }

    return sum;

}

 

int main()

{

    int i;

    long long ans;

    while(scanf("%d", &n), n)

    {

        memset(b, 0, sizeof(b));

        memset(c, 0, sizeof(c));

        for(i = 1; i <= n; i++)

        {

            scanf("%d", &a[i].num); //输入数值num

            a[i].id = i;            //记录序号id

        }

        ///开始离散化

        sort(a+1, a+n+1, cmp);  //先排序

        /*因为a[1].num是最小的,id是它的位置,所以b[a[1].id]=1最小,

          最小的数变成1,第二小的变成2,如此类推从而达到离散化*/

        b[a[1].id] = 1;

        for(i = 2; i <= n; i++)

        {

            if(a[i].num != a[i-1].num)

                b[a[i].id] = i;

            else b[a[i].id] = b[a[i-1].id];

        }

        ///离散化完毕

        ans = 0;

        for(i = 1; i <= n; i++)

        {

            update(b[i], 1);

            //这里很巧妙,每一次更新后,判断此数比左边的数小的数有多少

            ans += (sum(n)-sum(b[i]));

        }

        //从而求到:右边的数比左边的数大的个数的总和

        printf("%I64d\n", ans);

       //这里必须注意一下,数据比较大的话不用64位很容易出错,所以最好还是用64位输出

    }

 

    return 0;

}


       

      看到训练三一直关着,最近一直在看课件跟例题,我一直纳闷这么多天了训练三为什么一直关着。。。今晚上问了一下别人才知道还有一个开着的训练三。。。 很郁闷,很绝望。 然后今晚上的时间就先刷了两道A的最多的两道题,一道是二维树状数组问题,另一道是刚看的求逆序数的问题。

     从明天开始要正式开始刷题了!

     继续加油!




原创粉丝点击