题目大意:给定一组x[], 一组h[], 求所有的sum(min(h1,h2)*abs(x1,x2))。
解题报告:首先,h1,h2间的较小值,我们可以将h[]从大到小排序,每次取得的h都比先前的小,计算中用到的必然是当前取得h。至于abs(x1,x2),对于当前的x,查找所有比x小的数值的和,以及个数,以及所有比x大的数值的和,和个数,计算即可。
本题的数据规模是10W,为方便处理,可以不离散化x[]。
另外维护一棵线段树即可。查询数量时可以使用引用,在查询和的时候一起查询。树状数组也可以做。
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define LL long long
#define lson l,m,pos<<1
#define rson m+1,r,pos<<1|1
#define defm int m=(l+r)>>1;
const int maxn = 111111;
int num[maxn<<2];
LL sum[maxn<<2];
void updateFather(int pos)
{
sum[pos]=sum[pos<<1]+sum[pos<<1|1];
num[pos]=num[pos<<1]+num[pos<<1|1];
}
void update(int p,int val,int l,int r,int pos)
{
if(l==r)
{
sum[pos] = val;
num[pos] = 1;
return;
}
defm;
if(p<=m)
update(p,val,lson);
else
update(p,val,rson);
updateFather(pos);
}
LL query(int L,int R,int l,int r,int pos)
{
if(L<=l && r<=R)
return sum[pos];
defm;
return (L<=m?query(L,R,lson):0)+(m<R?query(L,R,rson):0);
}
LL query2(int &n,int L,int R,int l,int r,int pos)
{
if(L<=l && r<=R)
{
n+=num[pos];
return sum[pos];
}
defm;
return (L<=m?query2(n,L,R,lson):0)+(m<R?query2(n,L,R,rson):0);
}
struct Node
{
int xx;
int hh;
int h;
int x;
int xindex;
} p[maxn];
bool cmpx(const Node& a,const Node& b)
{
return a.x<b.x;
}
bool cmph(const Node& a,const Node& b)
{
return a.h<b.h;
}
void work(int n)
{
memset(sum,0,sizeof(sum));
memset(num,0,sizeof(num));
for(int i=0;i<n;i++)
scanf("%d%d",&p[i].x,&p[i].h);
sort(p,p+n,cmpx);
p[0].xx=1;
p[0].xindex = 1;
for(int i=1;i<n;i++)
{
if(p[i].x == p[i-1].x)
p[i].xx = p[i-1].xx;
else
p[i].xx = i+1;
p[i].xindex = i+1;
}
sort(p,p+n,cmph);
p[0].hh=1;
for(int i=1;i<n;i++)
{
if(p[i].h == p[i-1].h)
p[i].hh = p[i-1].hh;
else
p[i].hh = i+1;
}
LL res = 0;
for(int i=n-1;i>=0;i--)
{
int pos = p[i].xindex;
int ln = 0;
LL lsum = query2(ln,1,pos,1,n,1);
int rn = (n-1)-i-ln;
LL rsum = query(pos,n,1,n,1);
res+=(rsum-lsum-p[i].xx*(rn-ln))*(LL)p[i].hh;
update(pos,p[i].xx,1,n,1);
}
printf("%I64d\n",res);
}
int main()
{
// freopen("in.txt","r",stdin);
int n;
while(~scanf("%d",&n))
work(n);
}