Disharmony Trees HDU - 3015(树状数组)

传送门:QAQ

 

题意:给你一些树的高度和坐标,让你根据它的规则离散化后得到的树,每两个树都对应一个价值,价值的计算方法为min(h1,h2)*abs(x1-x2),然后让你输出任意两个树的价值和。

题意:首先我们观察这个式子,暴力就是n^2,我们首先发现需要的是两个树中小的高度,这样我们就可以先将树按高度排序,然后高度从大到小遍历,遍历到每个高度时,我们只要关心之前遍历过的树的abs(x1-x2)乘以当前的高度,这样我们就只要关心怎么统计abs(x1-x2)的值,这时候就想到用两个树状数组来统计,一个统计之前每个数出现的次数,一个统计之前每个数出现的和,然后当我们遍历到一个数时,我们就能处理有多少数是比它大的,有多少数是比它小的,然后又知道它们的和,遍历时更新树状数组,就可以算出来了(c++过的,g++过不了)

 

附上代码

#include<stdio.h>
#include<cmath>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cstring>
using namespace std;
const int INF = 0x3f3f3f3f;
#define LL long long int 
long long  gcd(long long  a, long long  b) { return a == 0 ? b : gcd(b % a, a); }
const int maxn = 100000+50;
int nn;
LL c[maxn];		//用于处理树状数组
LL lowbit(LL x)
{
	return (x)&(-x);
}
void update_onepos(LL pos, LL x)		//单点增加x
{
	while (pos <= nn)
	{
		c[pos] += x;
		pos += lowbit(pos);
	}
}
LL getsum_onepos(LL pos)		//区间求和 [1,x]
{
	LL sum = 0;
	while (pos > 0)
	{
		sum += c[pos];
		pos -= lowbit(pos);
	}
	return sum;
}
LL getsum_range(LL x1, LL x2)	//任意区间(x1,x2]求和
{
	return getsum_onepos(x2) - getsum_onepos(x1);
}
LL c1[maxn];	//用于处理树状数组
void update_onepos1(LL pos, LL x)		//单点增加x
{
	while (pos <= nn)
	{
		c1[pos] += x;
		pos += lowbit(pos);
	}
}
LL getsum_onepos1(LL pos)		//区间求和 [1,x]
{
	LL sum = 0;
	while (pos > 0)
	{
		sum += c1[pos];
		pos -= lowbit(pos);
	}
	return sum;
}
LL getsum_range1(LL x1, LL x2)	//任意区间(x1,x2]求和
{
	return getsum_onepos1(x2) - getsum_onepos1(x1);
}
struct inst {
	LL h;
	LL x;
	int id;
};
inst ax[110000];
long long cmp1(inst a, inst b) {
	if (a.x == b.x) return a.id < b.id;
	else 
		return a.x < b.x;
}
long long cmp2(inst a, inst b) {
	if (a.h == b.h) return a.id < b.id;
 	else 
		return a.h < b.h;
}
int main(void) {
	int n;
	nn = maxn;
	while (scanf("%d", &n) != EOF) {
		memset(c, 0, sizeof(c));
		memset(c1, 0, sizeof(c1));
		for (int i = 1; i <= n; i++) {
			scanf("%lld%lld", &ax[i].x, &ax[i].h);
			ax[i].id = i;
		}
		sort(ax + 1, ax + n + 1, cmp2);
		int t = ax[1].h;
		ax[1].h = 1;
		int num = 1;
		for (int i = 2; i <= n; i++) {
			if (ax[i].h != t) {
				num=i;
				t = ax[i].h;
				ax[i].h = num;
			}
			else ax[i].h = num;
		}
		sort(ax + 1, ax + n + 1, cmp1);
		t = ax[1].x;
		ax[1].x = 1;
		num = 1;
		for (int i = 2; i <= n; i++) {
			if (ax[i].x != t) {
				num=i;
				t = ax[i].x;
				ax[i].x = num;
			}
			else ax[i].x = num;
		}
		sort(ax + 1, ax + n + 1, cmp2);
		long long sum = 0;
		for (int i = n; i >= 1; i--) {
			if (i == n) {
				update_onepos(ax[i].x, ax[i].x);
				update_onepos1(ax[i].x, 1);
				continue;
			}
			else {
				//printf("%d\n%d\n%d\n%d\n", getsum_range1(ax[i].x, maxn), getsum_range1(0, ax[i].x - 1), getsum_range(ax[i].x, maxn), getsum_range(0, ax[i].x - 1));
				sum += abs(ax[i].h*(getsum_range1(ax[i].x-1, maxn)*(-ax[i].x) + getsum_range1(0, ax[i].x - 1)*ax[i].x + getsum_range(ax[i].x-1, maxn) - getsum_range(0, ax[i].x - 1)));
				//printf("**********%d\n", sum);
				update_onepos(ax[i].x, ax[i].x);
				update_onepos1(ax[i].x, 1);
			}
		}
		printf("%lld\n", sum);
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值