链接
http://acm.hdu.edu.cn/showproblem.php?pid=3015
题意
给你 n n n棵树,每棵树有两个属性 x x x坐标,及 h h h高度,现在定义 F = ∣ x i − x j ∣ F= |x_i\ -\ x_j| F=∣xi − xj∣,其中 x i x_i xi及 x j x_j xj均是 x x x的排名,如5、8、7、7,排名为1、4、2、2,定义 S = min ( h i , h j ) S=\min(h_i,\ h_j) S=min(hi, hj),其中 h i h_i hi及 h j h_j hj也是排名;现在需要你求出 ∑ i , j F ∗ S \displaystyle \sum_{i,j}F*S i,j∑F∗S,即所有任意两棵树的 F ∗ S F*S F∗S的和;
分析
这里考虑使用树状数组,首先, S S S是一个求最小值的操作,我们考虑将所有树按 h h h值从大到小排序,这样,当我们遍历到第 i i i棵树时,那么 h i h_i hi就是当前的 S S S,即第 i i i棵树与 i i i之前的任意一棵树的 S S S;
之后 S S S相同,我们考虑把 i i i与 i i i之前的 i − 1 i\ -\ 1 i − 1棵树的 F F F的和求出来,关键就是怎么求 F F F了,对于第 i i i棵树来说,它与之前所有树的 F = ∣ x i − x 1 ∣ + ∣ x i − x 2 ∣ + ⋅ ⋅ ⋅ + ∣ x i − x i − 1 ∣ F= |x_i\ -\ x_1|+|x_i\ -\ x_2|+···+|x_i\ -\ x_{i-1}| F=∣xi − x1∣+∣xi − x2∣+⋅⋅⋅+∣xi − xi−1∣;
在第 i i i棵树之前的树有两类,一类的排名 x > x i x>x_i x>xi,一类 x ≤ x i x\leq x_i x≤xi;之后我们使用两个树状数组,分别保存个数与和,即一个树状数组用来求 [ 1 , i − 1 ] [1,i-1] [1,i−1]中, x x x小于 x i x_i xi的个数(至于大于 x i x_i xi的个数,用 i i i直接减即可),另一个树状数组用来求 x x x小于 x i x_i xi的 x x x的和(至于大于 x i x_i xi的 x x x的和,直接拿当前总和减即可),我们就可以把两类给分开来了,分别求和即可,最后还要乘以一个当前树的 h i h_i hi,最后 i i i枚举到第 n n n棵树累加结果就可以了;
存结果的变量注意开 l o n g l o n g long\ long long long,不然会爆;
代码
#include <functional>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <set>
#include <map>
#define INF 0x7f7f7f7f
#define MAXN 100005
#define N 200005
#define P 2
#define MOD 99991
typedef long long ll;
namespace fastIO {
//#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1<<22, stdin), p1 == p2) ? EOF : *p1++)
//char buf[(1 << 22)], *p1 = buf, *p2 = buf;
inline int read() {
char c = getchar(); int x = 0, f = 1;
while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
}
using namespace fastIO;
using namespace std;
/*namespace segment_Tree {
struct Tree {
int l, r, max;
} tree[4 * MAXN];
inline void push_up(int x) {
tree[x].max = max(tree[x << 1].max, tree[x << 1 | 1].max);
}
inline void build(int x, int l, int r) {
tree[x].l = l, tree[x].r = r;
if (l == r) {
tree[x].max = 0;
return;
}
int mid = (l + r) >> 1;
build(x << 1, l, mid);
build(x << 1 | 1, mid + 1, r);
push_up(x);
}
inline void update(int x, int pos, int val) {
int l = tree[x].l, r = tree[x].r;
if (l == r) {
tree[x].max = max(tree[x].max, val);
return;
}
int mid = (l + r) >> 1;
if (pos <= mid)update(x << 1, pos, val);
else update(x << 1 | 1, pos, val);
push_up(x);
}
inline int query(int x, int l, int r) {
int le = tree[x].l, ri = tree[x].r;
if (l <= le && ri <= r) {
return tree[x].max;
}
int mid = (le + ri) >> 1;
int maxm = 0;
if (l <= mid) maxm = max(maxm, query(x << 1, l, r));
if (r > mid) maxm = max(maxm, query(x << 1 | 1, l, r));
return maxm;
}
}*/
struct tree {
int h, x;
bool operator<(const tree &a)const {
return h > a.h;
}
}t[MAXN];
int n, a[MAXN], b[MAXN], c1[MAXN], c2[MAXN];
void insert(int x, int val, int c[]) {
for (int i = x; i <= n; i += i & -i)
c[i] += val;
}
int sum(int x, int c[]) {
int res = 0;
for (int i = x; i > 0; i -= i & -i)
res += c[i];
return res;
}
int main() {
while (scanf("%d", &n)!=EOF) {
memset(c1, 0, sizeof(c1));
memset(c2, 0, sizeof(c2));
for (int i = 1; i <= n; i++)
a[i] = t[i].x = read(), b[i] = t[i].h = read();
sort(a + 1, a + 1 + n);
sort(b + 1, b + 1 + n);
sort(t + 1, t + 1 + n);
//这里不需要unique去重
ll res = 0;
for (int i = 1; i <= n; i++) {
int pos1 = lower_bound(a + 1, a + 1 + n, t[i].x) - a;
int rk = lower_bound(b + 1, b + 1 + n, t[i].h) - b;
//cout << rk << endl;
int sum1 = sum(pos1, c1);
int sum2 = sum(pos1, c2);
res += 1ll * rk * (1ll * sum1 * pos1 - sum2 + (sum(n, c2) - sum2) - 1ll * (i - sum1 - 1) * pos1);
insert(pos1, 1, c1);
insert(pos1, pos1, c2);
//cout << sum1 <<" " << sum2 <<" " <<res << endl;
}
cout << res << endl;
}
}