POJ 1990:MooFest(树状数组)

牛沟通成本算法解析

题目大意:有n头牛,第i头牛声调为v[i],坐标为x[i],任意两值牛i,j沟通所需的花费为abs(x[i]-x[j])*max(v[i],v[j]),求所有牛两两沟通的花费。

分析:

  我们将奶牛按声调升序排列,然后从前往后计算,由于奶牛i前面的奶牛声调都比它小,则最大声调被确定为v[i],然后只要计算之前所有奶牛与该奶牛距离即可。

  如何快速求出距离和?可以知道对于奶牛j,当它比奶牛i靠左时,其距离为(x[i]-x[j]),前面所有比i靠左的奶牛与奶牛i距离和为∑(x[i]-x[j])然而它也就是∑x[i]-∑x[j],前面一项等于x[i]*(左边奶牛个数),后一项就是左边奶牛坐标数值和,两者相减的到结果要乘v[i],右边的情况也一样,左右两边相加,就是这头牛与比它小的奶牛的花费,把每头牛的总花费加起来就是结果。

代码:

program fest;
var
  bit:array[1..2,0..20000]of int64;
  v,x:array[0..20000]of int64;
  n,m,s,a,b,t,g,ans:int64; i:longint;
procedure qsort(l,h:longint);
var i,j,t,m:longint;
begin i:=l; j:=h;
 m:=v[(i+j) div 2];
 repeat
while v[i]<m do inc(i);
while m<v[j] do dec(j);
if i<=j then
  begin   t:=v[i]; v[i]:=v[j]; v[j]:=t;t:=x[i]; x[i]:=x[j]; x[j]:=t;
inc(i); dec(j);  end;  until i>j;
 if i<h then qsort(i,h); if j>l then qsort(l,j);  end;
procedure add(l,i,k:longint);
begin
  while i<=m do
   begin
     inc(bit[l,i],k); inc(i,i and (-i));
   end;
end;
function query(l,i:longint):int64;
var s:longint;
begin
  s:=0;
  while i>0 do
   begin
     inc(s,bit[l,i]); dec(i,i and (-i));
   end;
  exit(s);
end;
begin
  assign(input,'fest.in');
reset(input);
assign(output,'fest.out');
rewrite(output);
  readln(n);
  for i:=1 to n do
  begin readln(v[i],x[i]);  if x[i]>m then m:=x[i]; end;
  qsort(1,n);
  for i:=1 to n do
   begin
     a:=query(1,x[i]); b:=query(2,x[i]);  s:=a*x[i]-b;
     t:=query(1,m)-a; g:=query(2,m)-b;  inc(s,g-x[i]*t);
     inc(ans,v[i]*s);
     add(1,x[i],1); add(2,x[i],x[i]);
   end;
  writeln(ans);
  close(input); close(output);
end.
View Code

 

转载于:https://www.cnblogs.com/qtyytq/p/5053858.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值