hdu3015 树状数组
有一天,索菲亚(Sophia)找到了一个很大的广场。广场上有n棵树。他们都很高。索菲娅对他们非常有趣。
她发现树可能不和谐,并且两棵树之间的不和谐值与两个值FAR和SHORT相关联。
FAR的定义如下:如果我们将所有这些树按照它们的X坐标按升序排列,则X坐标最小的树排名第一,X坐标相同的树排名相同。例如,如果有5棵树,它们的X坐标为3、3、1、3、4。那么他们的等级可能是2、2、1、2、5。X坐标为D1和D2的两棵树的FAR定义为F = abs(D1-D2)。
SHORT的定义类似于FAR。如果将所有这些树按照它们的高度升序排列,则高度最短的树排名第一。相同高度的树排名相同。例如,如果有5棵树的高度分别为4,1,9,7,4。那么他们的等级可能是2、1、5、4、2。高度等级为H1和H2的两棵树的SHORT定义为S = min(H1,H2)。
两棵树的不和谐值定义为F * S。因此,从上面的定义可以看出,如果两棵树的FAR较大,则不和谐值较大。Disharmony值也与两棵树中较短的一棵树相关。
现在为您提供每棵树的X坐标及其高度,请告诉Sophia所有树中每两棵树的Disharmony值的总和。
输入项
输入中有几个测试用例
对于每个测试用例,第一行包含一个整数N(2 <= N <= 100,000)N表示树的数量。
然后在N行之后,每行包含两个整数:X,H(0 <X,H <= 1,000,000,000),指示树位于坐标X中并且其高度为H.
对于每个测试用例,第一行包含一个整数N(2 <= N <= 100,000)N表示树的数量。
然后在N行之后,每行包含两个整数:X,H(0 <X,H <= 1,000,000,000),指示树位于坐标X中并且其高度为H.
输出量
对于每个测试用例,输出所有树中每两棵树的Disharmony值的总和。答案在带符号的64位整数内。
样本输入
2
10 100
20 200
4
10 100
50 500
20 200
20 100
样本输出
1
13
思路: 先按照题目意思排序得到数据的两个等级
因为求的是每两个树的F*S 所以 对h的等级 进行升序排序之后 保证的是当前的hh 就是最小的 h= min(h1,h2)
定义两个树状数组 c用来处理一个数前面或者后面比它大或者小的数之和,d用来处理这个数前面或者后面有多少个数
循环计算答案
当前第i个的 F*S=(xiao-da)*a[i].hh
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
struct node{
int x,h,xx,hh;
}a[maxn];
bool cmp1(node u,node v){
return u.x<v.x;
}
bool cmp2(node u,node v){
return u.h<v.h;
}
bool cmphh(node u,node v){
return u.hh<v.hh;
}
long long c[maxn],d[maxn],n;
//c用来处理一个数前面或者后面比它大或者小的数之和,d用来处理这个数前面或者后面有多少个数
int lowbit(int x)
{
return x&(-x);
}
void updatac(int i,int j)
{
while(i<=n)
{
c[i]+=j;
i+=lowbit(i);
}
}
void updatad(int i,int j)
{
while(i<=n)
{
d[i]+=j;
i+=lowbit(i);
}
}
long long getsumc(int x)
{
long long s=0;
while(x>0)
{
s+=c[x];
x-=lowbit(x);
}
return s;
}
long long getsumd(int x)
{
long long s=0;
while(x>0)
{
s+=d[x];
x-=lowbit(x);
}
return s;
}
int main(){
while(~scanf("%d",&n)){
for(int i=1;i<=n;i++){
scanf("%d %d",&a[i].x,&a[i].h);
}
sort(a+1,a+n+1,cmp1);
a[1].xx=1;
for(int i=2;i<=n;i++){
if( a[i].x==a[i-1].x ) a[i].xx=a[i-1].xx;
else a[i].xx=i;
}
int max=a[n].xx;
sort(a+1,a+n+1,cmp2);
a[1].hh=1;
for(int i=2;i<=n;i++){
if( a[i].h==a[i-1].h ) a[i].hh=a[i-1].hh;
else a[i].hh=i;
}
sort(a+1,a+1+n,cmphh);
// for(int i=1;i<=n;i++){
// cout<<a[i].x<<" "<<a[i].xx<<" "<<a[i].h<<" "<<a[i].hh<<endl;
// }
for(int i=1;i<=n;i++)
{
updatac(a[i].xx,a[i].xx);
updatad(a[i].xx,1);
}
long long sum=0,xiao,da;
for(int i=1;i<=n;i++)
{
xiao=getsumd(a[i].xx-1)*a[i].xx-getsumc(a[i].xx-1); //找出比这个数小的个数*这个数-比这个数小的所有数之和
da=(getsumd(max)-getsumd(a[i].xx))*a[i].xx-(getsumc(max)-getsumc(a[i].xx));
//找出比这个数大的数的和-这个数 * 比这个数大的个数
sum+=(xiao-da)*a[i].hh;
updatac(a[i].xx,-a[i].xx); //把这个用过的数从删除
updatad(a[i].xx,-1);//把这个数位置上减去1
}
printf("%I64d\n",sum);
}
return 0;
}

浙公网安备 33010602011771号