思路:
1.我们首先一下,计算出每棵树它的和的排名,用pair<int,int>
类型的数组存储每颗树,然后按的排名降序排列;
2.我们用降序排列好的数组,来一个个进行遍历;遍历之前我们应该先建好两个,两个树状数组的计算函数(cal(i,1)
和cal(i,0)
,其中i
代表位置,1
代表第一个树状数组,0
代表第二个树状数组)的意思分别为,已经遍历过的树中,小于的树的数量和这些树的总和;
3.每遍历到一颗树,我们计算这棵树和前面遍历过的每颗树的总和,已知我们是倒序排列的,因此当前树的和前面遍历的树的相比一定是最小的,因此此时所有的都是这棵树的;接下来就需要计算所有的总和了,我们现在根据两个树状数组可以得到先前遍历过的树中,小于当前树的的树的数量(cal(x-1,0)
),大于当前树的的树的数量(cal(n,0)-cal(x,0)
),小于当前树的的树的所有总和(cal(x-1,1)
),大于当前树的的树的所有总和(cal(n,1)-cal(x,1)
)(比较绕,请耐心理解),因此的总和计算公式就是cal(x-1,0)*x-cal(x-1,1)+(cal(n,1)-cal(x,1))-x*(cal(n,0)-cal(x,0))
;
代码:
#include<iostream>
#include<algorithm>
using namespace std;
template <class T>
inline bool read(T &ret){
char c; int sgn;
if(c=getchar(),c==EOF) return 0; //EOF
while(c!='-'&&(c<'0'||c>'9')) c=getchar();
sgn=(c=='-')?-1:1;
ret=(c=='-')?0:(c-'0');
while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
ret*=sgn; return 1;
}
typedef long long LL;
typedef pair<int,int> pii;
#define fi first
#define sc second
#define mp(a,b) make_pair(a,b)
const int MAX_N=1e5+5;
pii tree[MAX_N]; //fi represents h;sc represents x
int n,x[MAX_N],h[MAX_N];
int sum[MAX_N],num[MAX_N];
int cal(int i,int type){ //type:1 calculate the array of sum //type:0 array of num
int s=0;
while(i>0) s+=(type?sum[i]:num[i]),i-=i&-i;
return s;
}
void add(int i,int x,int type){
while(i<=n){
if(type) sum[i]+=x; else num[i]+=x;
i+=i&-i;
}
}
void init_hash(){
int xx[MAX_N],hh[MAX_N],rank_x[MAX_N],rank_h[MAX_N];
for(int i=0;i<n;i++) xx[i]=x[i],hh[i]=h[i];
sort(xx,xx+n); sort(hh,hh+n);
for(int i=0;i<n;i++){
tree[i].fi=lower_bound(hh,hh+n,h[i])-hh+1;
tree[i].sc=lower_bound(xx,xx+n,x[i])-xx+1;
}
sort(tree,tree+n,greater<pii>());
}
void solve(){
LL ans=0;
for(int i=0;i<n;i++){
int x=tree[i].sc;
LL S=1ll*tree[i].fi;
LL F=1ll*(cal(x-1,0)*x-cal(x-1,1)+cal(n,1)-cal(x,1)-x*(cal(n,0)-cal(x,0)));
ans+=S*F;
add(x,1,0); add(x,x,1);
}
cout<<ans<<'
';
for(int i=0;i<=n;i++) sum[i]=num[i]=0;
}
int main(){
while(read(n)){
for(int i=0;i<n;i++) read(x[i]),read(h[i]);
init_hash(); solve();
}
return 0;
}