bzoj 2752 线段树

题目:Y901高速公路是一条由N-1段路以及N个收费站组成的东西向的链,我们按照由西向东的顺序将收费站依次编号为1~N,从收费站i行驶到i+1(或从i+1行驶到i)需要收取Vi的费用。高速路刚建成时所有的路段都是免费的。政府部门根据实际情况,会不定期地对连续路段的收费标准进行调整,根据政策涨价或降价。
无聊的小A同学总喜欢研究一些稀奇古怪的问题,他开车在这条高速路上行驶时想到了这样一个问题:对于给定的l,r(l<r),在第l个到第r个收费站里等概率随机取出两个不同的收费站a和b,那么从a行驶到b将期望花费多少费用呢?

自己推出来独立做的一道题,很有满足感..=。=
先吐槽一下子:mdzz,明明草稿纸上还是加号,程序里就敲成了减号....
分母(总次数):len*(len+1)/2  (其中 len=r-l+1)
我们把每条边的边权放给它左边那个点,所以我们所有进行更新和询问的区间就变成了[l,r)
对于第i段(左右端点分别是i和i+1),对答案的贡献为  (i-l+1)*(r-i)* v[i] 
所以一段区间[l,r]的答案 = (r+l-1)sigma(v[i]*i)- sigma(v[i]*i*i) + (r-l*r)*sigma(v[i])    (其中,所有的i的范围为[l,r))
我们用线段树,维护三个和即可
type
        rec=record
           lazy,l,r:int64;
           sum:array[0..2] of int64;
end;

var
        m               :longint;
        i               :longint;
        x,y,t1,t2,tt,z,n:int64;
        t               :array[0..400010] of rec;
        ch              :char;

function gcd(a,b:int64):int64;
begin
   if b=0 then exit(a) else exit(gcd(b,a mod b));
end;

procedure build(x:longint;l,r:int64);
var
        mid:int64;
begin
   t[x].l:=l; t[x].r:=r;
   if l=r then exit;
   mid:=(l+r)>>1;
   build(2*x,l,mid); build(2*x+1,mid+1,r);
end;

procedure update(x:longint);
var
        tt:int64;
begin
   tt:=t[x].r-t[x].l+1;
   t[x].sum[0]:=t[x].sum[0]+t[x].lazy*tt;
   t[x].sum[1]:=t[x].sum[1]+t[x].lazy*(t[x].l+t[x].r)*tt div 2;
   t[x].sum[2]:=t[x].sum[2]+t[x].lazy*(((t[x].r*(t[x].r+1)*(2*t[x].r+1)) div 6) - (((t[x].l-1)*t[x].l*(2*t[x].l-1)) div 6));
   if t[x].l=t[x].r then
   begin
      t[x].lazy:=0; exit;
   end;
   inc(t[x*2].lazy,t[x].lazy);
   inc(t[2*x+1].lazy,t[x].lazy);
   t[x].lazy:=0;
end;

procedure change(x:longint;l,r,y:int64);
var
        mid:int64;
        len1,len2:int64;
begin
   if (t[x].l=l) and (t[x].r=r) then
   begin
      inc(t[x].lazy,y);exit;
   end;
   if t[x].lazy<>0 then update(x);
   mid:=(t[x].l+t[x].r)>>1;
   if r<=mid then change(2*x,l,r,y) else
     if l>mid then change(2*x+1,l,r,y) else
     begin
        change(2*x,l,mid,y);
        change(2*x+1,mid+1,r,y);
     end;
   len1:=t[2*x].r-t[2*x].l+1; len2:=t[2*x+1].r-t[2*x+1].l+1;
   t[x].sum[0]:=t[2*x].sum[0]+t[2*x+1].sum[0]
               +t[2*x].lazy*len1+t[2*x+1].lazy*len2;
   t[x].sum[1]:=t[2*x].sum[1]+t[2*x+1].sum[1]
               +t[2*x].lazy*(t[x*2].l+t[x*2].r)*len1 div 2
               +t[2*x+1].lazy*(t[x*2+1].l+t[x*2+1].r)*len2 div 2;
   t[x].sum[2]:=t[2*x].sum[2]+t[2*x+1].sum[2]
               +t[2*x].lazy*(((t[x*2].r*(t[x*2].r+1)*(2*t[x*2].r+1)) div 6) - (((t[x*2].l-1)*t[x*2].l*(2*t[x*2].l-1)) div 6))
               +t[2*x+1].lazy*(((t[x*2+1].r*(t[x*2+1].r+1)*(2*t[x*2+1].r+1)) div 6) - (((t[x*2+1].l-1)*t[x*2+1].l*(2*t[x*2+1].l-1)) div 6));
end;

function find(x:longint;l,r:int64;p:longint):int64;
var
        mid:int64;
begin
   if t[x].lazy<>0 then update(x);
   if (t[x].l=l) and (t[x].r=r) then exit(t[x].sum[p]);
   mid:=(t[x].l+t[x].r)>>1;
   if r<=mid then exit(find(2*x,l,r,p)) else
     if l>mid then exit(find(2*x+1,l,r,p)) else
       exit(find(2*x,l,mid,p)+find(2*x+1,mid+1,r,p));
end;

begin
   read(n,m);readln;
   build(1,1,n-1);
   for i:=1 to m do
   begin
      read(ch);
      if ch='C' then
      begin
         readln(x,y,z);
         change(1,x,y-1,z);
      end else
      begin
         readln(x,y);
         t2:=(y-x+1)*(y-x) div 2;
         t1:=(y+x-1)*find(1,x,y-1,1)-find(1,x,y-1,2)+(y-x*y)*find(1,x,y-1,0);
         if t1<t2 then tt:=gcd(t2,t1) else tt:=gcd(t1,t2);
         writeln(t1 div tt,'/',t2 div tt);
      end;
   end;
end.
——by Eirlys


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值