树状数组-HDU3015 Disharmony Trees

算法 专栏收录该内容
36 篇文章 0 订阅

树状数组


  • 什么是树状数组?
    简单来说,就是暴力遍历数组来解决区间问题等,不过遍历的路径使用了位运算来进行压缩,复杂度是O(log2(n))这样就不会超时了(为所欲为?)。
  • lowbit()操作
    其核心是神奇的lowbit操作,lowbit(x)=x&(-x),它的功能是找到x的二进制数的最后一个1,原理是利用负数的补码表示,补码是原码取反加一。例如x=6=00000110(2),-x=x补=11111010(2),那么lowbit(x)=x&(-x)=10(2)=2。
    从lowbit()引出数组a[],a[x]的值是把ax(题目输入初始值)和他前面的m个数相加,如下表所示:
    在这里插入图片描述
    图形化:
    在这里插入图片描述
    那么通过数组a[],就可以求sum,例如sum(8)=a[8],sum(7)=a[7]+a[6]+a[4],sum(6)=a[6]+a[4],如此一来不就是我们要的路径压缩了吗?
    同样地,更新ax时也要更新a[],例如更新a3,那么首先更改a[3];然后3+lowbit(3)=4,更改a[4];接着4+lowbit(4)=8,更改a[8]。

例题


传送门: HDU-3015

One day Sophia finds a very big square. There are n trees in the square. They are all so tall. Sophia is very interesting in them.
在这里插入图片描述
She finds that trees maybe disharmony and the Disharmony Value between two trees is associated with two value called FAR and SHORT.
The FAR is defined as the following:If we rank all these trees according to their X Coordinates in ascending order.The tree with smallest X Coordinate is ranked 1th.The trees with the same X Coordinates are ranked the same. For example,if there are 5 tree with X Coordinates 3,3,1,3,4. Then their ranks may be 2,2,1,2,5. The FAR of two trees with X Coordinate ranks D1 and D2 is defined as F = abs(D1-D2).
The SHORT is defined similar to the FAR. If we rank all these trees according to their heights in ascending order,the tree with shortest height is ranked 1th.The trees with the same heights are ranked the same. For example, if there are 5 tree with heights 4,1,9,7,4. Then their ranks may be 2,1,5,4,2. The SHORT of two trees with height ranks H1 and H2 is defined as S=min(H1,H2).
Two tree’s Disharmony Value is defined as F*S. So from the definition above we can see that, if two trees’s FAR is larger , the Disharmony Value is bigger. And the Disharmony value is also associated with the shorter one of the two trees.
Now give you every tree’s X Coordinate and their height , Please tell Sophia the sum of every two trees’s Disharmony value among all trees.

input:

There are several test cases in the input
For each test case, the first line contain one integer N (2 <= N <= 100,000) N represents the number of trees.
Then following N lines, each line contain two integers : X, H (0 < X,H <=1,000,000,000 ), indicating the tree is located in Coordinates X and its height is H.

output:

For each test case output the sum of every two trees’s Disharmony value among all trees. The answer is within signed 64-bit integer.

Sample Input:

2
10 100
20 200
4
10 100
50 500
20 200
20 100

Sample Output:

1
13

题意

给出N棵树的坐标X和高度H,定义两棵树的不和谐值为FAR*SHORT,其中FAR=abs(x1-x2),SHORT=min(h1,h2),注意此时的x,h是排序后的排名,且有同名情况。求总的不和谐值。

分析

  1. 数据处理:
    读入pair<坐标X,原始下标>x[],排序后处理同名情况,高度H同理,最后拼接得到pair<相对坐标,相对高度>p[]。
  2. 维护两个树状数组:
    因为SHORT=min(h1,h2),那我们对p[]按高度降序排序,然后遍历p[],每次即得到了当前的最小高度SHORT,然后乘上之前所有树的FAR即可。
    那么FAR怎么求呢???
    此时维护数组cnt[]表示数量,dis[]表示坐标,总FAR=FAR左+FAR右(因为是按高度排序,不是坐标,所以有左右之分),FAR左=左边树的数量×当前树坐标-左边树的坐标和,就得到了左边所有树到当前树的距离;
    同样的,FAR右=右边树的坐标和-右边树的数量×当前树的坐标。
    至此维护数组更新答案就好了。

代码

#include<cstdio>
#include<algorithm>
#include<string.h>
using namespace std;
typedef long long ll;
const int maxn = 100005;
pair<ll, ll>p[maxn], x[maxn], h[maxn];
int n;
ll cnt[maxn], dis[maxn];
bool cmp(pair<ll, ll>a, pair<ll, ll>b) {
	return a.second > b.second;
}
int lowbit(int x) {
	return x & (-x);
}
ll sum(ll* bit, int x) {
	ll res = 0;
	for (int i = x; i > 0; i -= lowbit(i))
		res += bit[i];
	return res;
}
ll sum(ll* bit, int from, int to) {
	return sum(bit, to - 1) - sum(bit, from - 1);
}
void update(ll* bit, int x, ll y) {
	for (int i = x; i <= maxn; i += lowbit(i))
		bit[i] += y;
}
int main() {
	while (~scanf("%d", &n)) {
		//1.数据处理
		for (int i = 1; i <= n; i++) {
			scanf("%lld%lld", &x[i].first, &h[i].first);
			x[i].second = h[i].second = i;
		}
		sort(x + 1, x + n + 1);
		sort(h + 1, h + n + 1);
		ll tx = x[1].first, th = h[1].first, ans = 0;
		x[1].first = h[1].first = 1;
		for (int i = 2; i <= n; i++) {//同名处理
			if (x[i].first == tx)
				x[i].first = x[i - 1].first;
			else {
				tx = x[i].first;
				x[i].first = i;
			}
			if (h[i].first == th)
				h[i].first = h[i - 1].first;
			else {
				th = h[i].first;
				h[i].first = i;
			}
		}
		for (int i = 1; i <= n; i++) {
			p[x[i].second].first = x[i].first;
			p[h[i].second].second = h[i].first;
		}
		//2.维护两个树状数组
		sort(p + 1, p + 1 + n, cmp);//高度降序
		memset(cnt, 0, sizeof(cnt));
		memset(dis, 0, sizeof(dis));
		for (int i = 1; i <= n; i++) {
			ll cx = p[i].first, ch = p[i].second;//当前树坐标和高度
			ll left = sum(cnt, 1, cx), right = sum(cnt, cx + 1, maxn);//左边树的数量和右边树的数量
			ans += ch * (left * cx - sum(dis, 1, cx) + sum(dis, cx + 1, maxn) - right * cx);
			update(cnt, cx, 1);//更新数量
			update(dis, cx, cx);//更新坐标
		}
		printf("%lld\n", ans);
	}
	return 0;
}

小结


看见求和,坐标等关键词时,普通模拟会超时则可以考虑转换成树状数组题型来求解,重点是如何转换,若要用到多个树状数组时,一般会有最值比较排序。

相关推荐


题目推荐:

博文推荐

原创不易,请勿转载本不富裕的访问量雪上加霜
博主首页:https://blog.csdn.net/qq_45034708
如果文章对你有帮助,记得关注点赞收藏❤

  • 4
    点赞
  • 0
    评论
  • 3
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 护眼 设计师:闪电赇 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值