转载请注明出处:忆梦http://blog.youkuaiyun.com/yimeng2013/article/details/13510899
题意:有一排树每一棵都有两个值X,H。 要求这一排树的“不和谐”值;
计算规则:每两棵树的F*S的值之和;
F的定义: F = abs(D1 - D2),即两棵树的x值经过排序(离散化)后的差的绝对值,排序的规则如题示例
x坐标为3,3,1,3,4的一排树,他们的rank值D为2,2,1,2,5
S的定义: S = min(H1,H2),即两棵树的H值经过排序后的最小值(排序规则同上);
思路:将树以H值从小到大的顺序来排列,那么对于每一棵树的S就一定等于这棵树的H值。
对于求这棵树的F值:F = (D*cnt_small - small) + (big - D*cnt_big);
其中的D为该棵树的D值,而cnt_small ,cnt_big为这棵树之后比它小,大的树的棵树,samll和big为这 棵树之后比它小,大的树的D值和;
A了这道题太爽了,想了差不多三天,又花了几个小时敲,竟然1A了,感觉树状数组总算是入门了。
详细的构思请看代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
#define LL __int64
#define N 100000+10
int n;
LL cnt[N];
LL pre[N];
int lowbit(int x)
{
return x & -x;
}
int sum(LL a[],int x)
{
int ret = 0;
while(x > 0)
{
ret += a[x];
x -= lowbit(x);
}
return ret;
}
void add(LL a[],int x, int d)
{
while(x <= n)
{
a[x] += d;
x += lowbit(x);
}
}
struct Node
{
int x;
int y;
}node[N];
int cmp1(Node a, Node b)
{
return a.x < b.x;
}
int cmp2(Node a, Node b)
{
return a.y > b.y;
}
int main ()
{
while(scanf("%d", &n) != EOF)
{
for(int i = 1; i <= n; i++)
{
scanf("%d %d", &node[i].x, &node[i].y);
}
//离散化
sort(node+1, node+1+n, cmp1);
int pree = -1, rank;
for(int i = 1; i <= n; i++)
{
if(node[i].x != pree)
{
pree = node[i].x;
node[i].x = i;
rank = i;
}
else
{
node[i].x = rank;
}
}
sort(node+1, node+1+n, cmp2);
pree = -1, rank;
for(int i = n; i >= 1; i--)
{
if(node[i].y != pree)
{
pree = node[i].y;
node[i].y = n - i + 1;
rank = n - i + 1;
}
else
{
node[i].y = rank;
}
}
memset(cnt, 0, sizeof(cnt));
memset(pre, 0, sizeof(pre));
LL ans = 0;
for(int i = 1; i <= n; i++)
{
LL totle = 0;
LL small = 0, big = 0;
LL cnt_small = 0, cnt_big = 0;
add(cnt, node[i].x, 1);
add(pre, node[i].x, node[i].x);
LL temp = sum(cnt,node[i].x) - sum(cnt, node[i].x-1);//计算出X值相同的树的个数
totle = sum(pre, n);//计算出1~i棵树的x值的和
small = sum(pre, node[i].x-1);//计算出第i棵树之前比第i棵树的x值小的树的x值之和
big = totle - small - node[i].x*temp;//计算出第i棵树之前比第i棵树的x值大的树的x值之和
cnt_small = sum(cnt, node[i].x-1);//计算出第i棵树之前比第i棵树小的树的个数
cnt_big = i - cnt_small- temp ;//计算出第i棵树值前比第i棵树大的树的个数
ans += node[i].y * ((cnt_small*node[i].x - small ) + (big - cnt_big*node[i].x));
}
printf("%I64d\n", ans);
}
}