POJ - 1990 MooFest 解题报告(两个树状数组)

题目描述

链接:https://vjudge.net/problem/POJ-1990
题目有点难读,但我就是想偷个懒~

思路分析

这道题有点像求逆序数的那道题。
首先,因为它要的两个因素(max(val)和abs(dis))里,和顺序有关的主要是max(val),那么我们就想到对它按照val进行排序:保证现在加入树中的元素的val最大。之后,就和逆序数的思路一样,加入一个,然后通过树状数组计算出两边的位置和,和目前这个牛的位置处理一下出来距离和,然后就能得到关于这头牛的max(val)*abs(dis)。
通过这两道题加深了对树状数组的理解:其实他就是个维护数据的结构,我们可以做的操作就是单点修改的区间求和,我们就把它当作存取数据的东西就行了,不用考虑过多。

代码

#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
#define lowbit(x) ((x)&-(x))
const int maxn=20005;
typedef long long ll;
struct cow{
	int v;//价值 
	int i;//距离 
	bool operator<(cow n){
		if(v==n.v){
			return i<n.i;
		}
		return v<n.v;
	}
};
ll tree1[maxn];//存数量 以距离为键 
ll tree2[maxn];//存距离 以距离为键
cow data[maxn];
int n;

void add1(ll x,ll num){//对tree1操作 
	while(x<maxn){
		tree1[x]+=num;
		x+=lowbit(x);
	}
}

void add2(ll x,ll num){//对tree2操作,下同 
	while(x<maxn){
		tree2[x]+=num;
		x+=lowbit(x);
	}
}

ll sum1(ll x){
	ll ans=0;
	while(x>0){
		ans+=tree1[x];
		x-=lowbit(x);
	}
	return ans;
}

ll sum2(int x){
	ll ans=0;
	while(x>0){
		ans+=tree2[x];
		x-=lowbit(x);
	}
	return ans;
}

int main()
{
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		scanf("%d %d",&data[i].v,&data[i].i);
	}
	sort(data,data+n);//按照val升序排序 
	ll ans=0; 
	for(int i=0;i<n;i++){
		int v=data[i].v;//因为按照val的升序排序,所以当前的val肯定是最大的 
		int d=data[i].i;
		ll numl=sum1(d-1);//左边牛的数量 
		ll numr=sum1(maxn)-sum1(d);//右边牛的数量 
		ll dsl=sum2(d-1);
		ll ds2=sum2(maxn)-sum2(d);
		ans+=v*(d*numl-dsl+ds2-d*numr); 
		add1(d,1);
		add2(d,d);
	}
	printf("%lld\n",ans);
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值