标签:树状数组
提议是给你一个序列 让你调整把它变成 从小到大排列的有序序列 没调动两个为两权值之和 问最小的权值和是多少
给个数列 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; }
标签:树状数组
原文地址:http://blog.csdn.net/zxf654073270/article/details/42585087