传送门: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;
}