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]。

# 例题

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


## 分析

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;
}


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

08-08 329
04-19 293

09-08 287
11-30 149
08-21 747
05-08 504
08-19 111
08-09 662
09-30 576
07-14 58
01-21 133
09-29 1304
12-30 29