题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3015
题意:给你n颗树的位置和高度,要求把这n棵树的位置和高度离散化以后,求 ∑ \sum_{} ∑abs(xi-xj)*min(hi,hj)(i<j)
思路:首先将每棵树的坐标和位置按照题目的要求离散化以后,按照高度从大到小对这n棵树进行排序,那样的对于每一个i,1->i中第i棵树的h就是最小的,接下来就要考虑1->i-1与i的x的差的绝对值的和。那我们就要考虑1->i-1中比a[i].x大和比a[i].x小两部分啦,那我们就可以考虑使用树状数组求逆序对个数的思路,用一个数组sum[]存储1->i-1中比a[i].x小的个数,ans[]存储1->i-1中比a[i].x小的数的值,那我们每次计算时就可以对比a[i].x大和比a[i].x小的分开求啦,如下:
LL sum1=query(a[i].x,sum);//i之前比a[i].x小的数的个数
LL ans1=query(a[i].x,ans);//i之前比a[i].x小的数的和
LL sum2=query(n,sum);//总的个数
LL ans2=query(n,ans);//总的和
LL temp1=a[i].x*sum1-ans1;//比a[i].x小的
LL temp2=ans2-ans1-a[i].x*(sum2-sum1)//比a[i].x大的
然后每次计算完以后记得更新一下sum[]和ans[]的值就行
具体代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL long long
const int maxn=1e5+7;
struct node
{
LL x,h;
}a[maxn];
LL X[maxn],H[maxn];
bool cmp(node aa,node bb)
{
if(aa.h==bb.h) return aa.x<bb.x;
return aa.h>bb.h;
}
int n;
LL sum[maxn],ans[maxn];
int lowbit(int x)
{
return x&(-x);
}
void update(int x,LL val,LL aa[])
{
for(int i=x;i<=n;i+=lowbit(i))
{
aa[i]+=val;
}
}
LL query(int x,LL aa[])
{
LL res=0;
for(int i=x;i;i-=lowbit(i))
{
res+=aa[i];
}
return res;
}
int main()
{
while(~scanf("%d",&n))
{
for(int i=1;i<=n;i++)
{
scanf("%lld%lld",&a[i].x,&a[i].h);
X[i]=a[i].x,H[i]=a[i].h;
}
sort(X+1,X+n+1),sort(H+1,H+n+1);
for(int i=1;i<=n;i++)
{
a[i].x=lower_bound(X+1,X+n+1,a[i].x)-X;
a[i].h=lower_bound(H+1,H+n+1,a[i].h)-H;
}
sort(a+1,a+n+1,cmp);
memset(sum,0,sizeof(sum));
memset(ans,0,sizeof(ans));
LL ANS=0;
for(int i=1;i<=n;i++)
{
LL sum1=query(a[i].x,sum);
LL ans1=query(a[i].x,ans);
LL sum2=query(n,sum);
LL ans2=query(n,ans);
ANS+=(a[i].x*sum1-ans1+ans2-ans1-a[i].x*(sum2-sum1))*a[i].h;
update(a[i].x,1LL,sum);
update(a[i].x,a[i].x,ans);
}
printf("%lld\n",ANS);
}
return 0;
}