Description
n头奶牛站成一条直线(编号为1..n),第i头奶牛的位置用坐标x[i]表示,奶牛i,j之间的距离定义为dist(i,j)=|x[i]-x[j]|。第i头奶牛的听力值为v[i],那么奶牛i,j之间要相互交谈,她们的声音不能小于MAX(v[i],v[j])*dist(i,j)。
现在每对奶牛都在交谈,并且使用最小的音量,那么所有n(n-1)/2头奶牛间谈话的音量之和为多少?
Input
第1行一个整数n,表示有n头奶牛。接下来的n行,每行表示一头奶牛的信息v[i]和x[i]。
Output
n头奶牛站成一条直线(编号为1..n),第i头奶牛的位置用坐标x[i]表示,奶牛i,j之间的距离定义为dist(i,j)=|x[i]-x[j]|。第i头奶牛的听力值为v[i],那么奶牛i,j之间要相互交谈,她们的声音不能小于MAX(v[i],v[j])*dist(i,j)。
现在每对奶牛都在交谈,并且使用最小的音量,那么所有n(n-1)/2头奶牛间谈话的音量之和为多少?
Input
第1行一个整数n,表示有n头奶牛。接下来的n行,每行表示一头奶牛的信息v[i]和x[i]。
Output
一行一个整数,表示最后的答案。
分析:
设一个结构体:{x,v},x表示位置,v表示声音。按照v从大到小排序。
奶牛1到奶牛2,3,4……n的音量和为:v[1]*sum| x[1]-x[i] | 。奶牛2-n同理。
设n1为x小于x[i]的数量,n2为x大于x[i]的数量,sum1为x小于x[1]的x之和,sum2为大于的和,那么上式就是:v[1]*(n1*x[1]-sum1)+v[1]*(sum2-n2*x[1]) ;
至此可以明确:建立权值线段树,维护两个数据:num[i]表示i代表的区间里有多少个数,sum[i]表示i代表的区间里x的和。
每个奶牛算完后,把这头奶牛删掉。
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
const int INF=200005;
const int maxn=50005;
int n,rt=0,np=0,lc[INF*2],rc[INF*2],num[INF*2];
LL sum[INF*2];
struct data{int v,x;}cow[maxn];
bool cmp(data a,data b) {return a.v>b.v;}
void build(int &now,int L,int R)
{
now=++np;
if(L==R) return;
int m=(L+R)/2;
build(lc[now],L,m);
build(rc[now],m+1,R);
}
void pushup(int now,int L,int R)
{
num[now]=num[L]+num[R];
sum[now]=sum[L]+sum[R];
}
void update(int now,int L,int R,int x,int d)
{
if(L==R)//L=R=x
{
num[now]+=d;
sum[now]+=x*d;
return;
}
int m=(L+R)/2;
if(x<=m) update(lc[now],L,m,x,d);
else update(rc[now],m+1,R,x,d);
pushup(now,lc[now],rc[now]);
}
int Count1(int now,int L,int R,int x)
{
if(L==R) return 0;
int m=(L+R)/2,t=num[lc[now]];
if(x<=m) return Count1(lc[now],L,m,x);
return t+Count1(rc[now],m+1,R,x);
}
int Count2(int now,int L,int R,int x)
{
if(L==R) return 0;
int m=(L+R)/2,t=num[rc[now]];
if(x<=m) return t+Count2(lc[now],L,m,x);
return Count2(rc[now],m+1,R,x);
}
int Kth(int now,int L,int R,int k)
{
if(L==R) return L;
int m=(L+R)/2,t=num[lc[now]];
if(k<=t) return Kth(lc[now],L,m,k);
return Kth(rc[now],m+1,R,k-t);
}
LL Sum(int now,int L,int R,int i,int j)
{
if(i<=L&&j>=R) return sum[now];
int m=(L+R)/2;
LL ans=0;
if(i<=m) ans+=Sum(lc[now],L,m,i,j);
if(j>m) ans+=Sum(rc[now],m+1,R,i,j);
return ans;
}
int main()
{
// freopen("in.txt","r",stdin);
scanf("%d",&n);
build(rt,0,INF);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&cow[i].v,&cow[i].x);
update(rt,0,INF,cow[i].x,1);//每头牛的x加入集合
}
sort(cow+1,cow+1+n,cmp);//按照v排序
LL ans=0;
for(int i=1;i<=n;i++)
{
int v=cow[i].v;
int n1=Count1(rt,0,INF,cow[i].x);//小于x[i]的个数
int n2=Count2(rt,0,INF,cow[i].x);//大于x[i]的个数
int k1=Kth(rt,0,INF,n1);//恰好小于x[i]的数
int k2=Kth(rt,0,INF,n1+1+n2);//恰好大于x[i]的数
LL sum1=Sum(rt,0,INF,0,k1);//x[i]之前的x之和
LL sum2=Sum(rt,0,INF,cow[i].x+1,k2);//x[i]之后的x之和
ans+=(LL)v*((LL)n1*cow[i].x-sum1+sum2-(LL)n2*cow[i].x);//统计答案
update(rt,0,INF,cow[i].x,-1);//删掉这头奶牛
}
printf("%lld",ans);
return 0;
}