首页 > 代码库 > hdu 2838 树状数组水题

hdu 2838 树状数组水题

提议是给你一个序列   让你调整把它变成 从小到大排列的有序序列    没调动两个为两权值之和   问最小的权值和是多少


给个数列   1 4 2 3 5      对每一个位置数   需要交换的比为前面比它大的数  或后面比它小的数(包含了最小值在里面了)     比如pi前面有5个数比它大   则就需要把这5个数和pi交换   交换的权值就是这5个数的和再加上5*pi      庵后对每个数都这样求就为最后结果      我是把它倒过来然后按求逆序数的方式 求     有两个更新和查询


cont表示前面比它小的个数   sum表示前面比它小的数的和;

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;

int n,cont[100010],num[100010];
__int64  sum[100010];
int update(int a,int b)
{
    for(int i=a;i<=n;i+=(i&-i))
    cont[i]+=b;
    return 0;
}
int add(int a,int b)
{
    for(int i=a;i<=n;i+=(i&-i))
    sum[i]+=b;
    return 0;        
}
__int64 find1(int a)
{
    __int64 s=0;
    for(int i=a;i>=1;i-=(i&-i))
    s+=cont[i];
    return s;    
}
__int64 find2(int a)
{
    __int64    s=0;
    for(int i=a;i>=1;i-=(i&-i))
    s+=sum[i];
    return s;
}
int main()
{
    int i,j;
    while(~scanf("%d",&n))
    {
        memset(sum,0,sizeof(sum));
        memset(cont,0,sizeof(cont));
        __int64 Sum=0;
        int m;
        for(i=1;i<=n;i++)
        scanf("%d",&num[i]);
        for(i=n;i>=1;i--)
        {
            __int64 t1=find1(num[i]);
            __int64 t2=find2(num[i]);
            Sum+=t1*num[i]+t2;
            update(num[i],1);
            add(num[i],num[i]);    
        }
        printf("%I64d\n",Sum);
    }        
    return 0;
}

hdu 2838 树状数组水题