利用树状数组(对数组左侧比数组小的点的个数进行维护)

题目链接http://acm.hdu.edu.cn/showproblem.php?pid=5775

题意:T组数组,长度为n的数组,n个元素属于[1,n]不重复,即是1-n全排列中的一种。对其进行冒泡排序,问在冒泡排序的过程中从1-n的数字所到达的最右边的点减去最左边的点的距离

分析:每个数字i都有一个初始位置,和一个结束位置,按数字i不方便,仍按照数组a[i]。a[i]中i +1表示a[i]这一数字初始的位置,而i表示结束的位置,在冒泡排序的过程中初始位置将会右移,右移的个数为在a[i]右边比a[i]小的个数。如果直接统计个数会超时,利用树状数组来维护在其右边比其小的个数。最左边的点为a[i],i + 1中较小者。最右边的点为a[i],和i + 在其右边比其小的个数  中的较大者。

树状数组:裸

代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
int tree[400005];
int a[100005];
int ans[100005];
int n;
void add(int k)
{
    while(k <= n)
    {
        tree[k] ++;
        k += k & (- k);
    }
}
int read(int k)
{
    int ans = 0;
    while(k)
    {
        ans += tree[k];
        k -= k &(-k);

    }
    return ans;
}
int main()
{
    //freopen("in.txt","r",stdin);
    int T;
    scanf("%d",&T);
    for(int t = 1; t <= T; t ++)
    {
        memset(tree,0,sizeof(tree));
        scanf("%d",&n);
        for(int i = 1; i <= n; i ++)
        {
            scanf("%d",&a[i]);
        }
        int l,r;
        for(int i = n; i >= 1; i --)
        {
            add(a[i]);
            l = min(i,a[i]);
            r = max(a[i],i + read(a[i] - 1));
            ans[a[i]] = fabs(r - l);
        }
        printf("Case #%d:",t);
        for(int i = 1; i <= n; i ++)
        {
            printf(" %d",ans[i]);
        }
        printf("\n");
    }

    return 0;
}


你可能感兴趣的:(树状数组,数据结构)