HDU 3015 Disharmony Trees(树状数组)

思路:

1.我们首先 h a s h hash hash一下,计算出每棵树它的 x x x h h h的排名,用pair<int,int>类型的数组存储每颗树,然后按 h h h的排名降序排列;
2.我们用降序排列好的数组,来一个个进行遍历;遍历之前我们应该先建好两个 B I T BIT BIT,两个树状数组的计算函数(cal(i,1)cal(i,0),其中i代表位置,1代表第一个树状数组,0代表第二个树状数组)的意思分别为,已经遍历过的树中, x x x小于 i i i的树的数量和 a n d and and这些树的 x x x总和;
3.每遍历到一颗树,我们计算这棵树和前面遍历过的每颗树的 S ∗ F S*F SF总和,已知我们是倒序排列的 h h h,因此当前树的 h h h和前面遍历的树的 h h h相比一定是最小的,因此此时所有的 S S S都是这棵树的 h h h;接下来就需要计算所有 S S S的总和了,我们现在根据两个树状数组可以得到先前遍历过的树中, x x x小于当前树的 x x x的树的数量(cal(x-1,0)), x x x大于当前树的 x x x的树的数量(cal(n,0)-cal(x,0)), x x x小于当前树的 x x x的树的所有 x x x总和(cal(x-1,1)), x x x大于当前树的 x x x的树的所有 x x x总和(cal(n,1)-cal(x,1))(比较绕,请耐心理解),因此 S S S的总和计算公式就是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<<'\n';
	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;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值