hdu3015 树状数组

蓝咒 提交于 2019-12-05 01:03:10

有一天,索菲亚(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.
 
输出量
对于每个测试用例,输出所有树中每两棵树的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;
}

  

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!