题目大意:
有一排acm大牛(20,000),告诉你他们每个人的听力水平和所在位置坐标,并且他们每个人之间交流都需要的声音大小为:他们之间的距离乘他们两个人听力水平的较大值。现在问你每一对牛都交流一次,并且他们交流都是用的能交流的最小的声音,请算出他们这个活动产生的各种声音的大小的总和(应该是相同大小的声音多次出现分别都加上)。
分析:
至少要求出每两个牛交流产生的声音值
话说上面的也没用到树状数组啊,这怎么能行。再考虑一个问题,比如所需声音最大的和其他的所有牛交流一次,产生的声音的总和为:
具体的代码实现技巧就是,用两个树状数组,一个记录坐标和,一个记录个数。求一个点右面的和等于树状数组总和减这个点左面的和。
代码:
#include<iostream>
#include<string.h>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#define maxn 20500
using namespace std;
struct xcx
{
int x;
int v;
}cow[maxn];
int n;
long long int tree[3][maxn]={0};//tree[1]计算有多少个,tree[2]计算坐标和是多少
bool my_cmp(xcx x,xcx y)
{
return x.v<y.v;
}
int lowbit(int x)
{
return x&(-x);
}
void add(int x)//加上坐标为x的一个点
{
int t=x;
while(x<=maxn)
{
tree[1][x]+=1;
tree[2][x]+=t;
x+=lowbit(x);
}
}
long long int sum(int i,int x)//i=1求个数,i=2求坐标和
{
long long int s=0;
while(x>0)
{
s+=tree[i][x];
x-=lowbit(x);
}
return s;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&cow[i].v,&cow[i].x);
}
sort(cow+1,cow+n+1,my_cmp);
/*for(int i=1;i<=n;i++) { cout<<cow[i].v<<endl; }*/
long long int best=0;
for(int i=1;i<=n;i++)
{
long long int l,r;
l=sum(1,cow[i].x)*cow[i].x-sum(2,cow[i].x);
r=sum(2,maxn)-sum(2,cow[i].x)-(sum(1,maxn)-sum(1,cow[i].x))*cow[i].x;
best+=cow[i].v*(l+r);
//cout<<l<<" "<<r<<" "<<best<<endl;
add(cow[i].x);
}
cout<<best<<endl;
}
后注:
这次完全自己思路,一次ac,爽~
注意回来要仔细研究一下离线处理的思想。