zoukankan      html  css  js  c++  java
  • NOIP2015普及组 Luogu 2672 CodeVS 5126 推销员-线段树-Pascal

    题目描述 Description

    阿明是一名推销员,他奉命到螺丝街推销他们公司的产品。螺丝街是一条死胡同,出口与入口是同一个,街道的一侧是围墙,另一侧是住户。螺丝街一共有N家住户,第i家住户到入口的距离为Si米。由于同一栋房子里可以有多家住户,所以可能有多家住户与入口的距离相等。阿明会从入口进入,依次向螺丝街的X家住户推销产品,然后再原路走出去。阿明每走1米就会积累1点疲劳值,向第i家住户推销产品会积累Ai点疲劳值。阿明是工作狂,他想知道,对于不同的X,在不走多余的路的前提下,他最多可以积累多少点疲劳值。

    输入描述 Input Description

    第一行有一个正整数N,表示螺丝街住户的数量。
    接下来的一行有N个正整数,其中第i个整数Si表示第i家住户到入口的距离。数据保证S1≤S2≤…≤Sn<10^8。
    接下来的一行有N个正整数,其中第i个整数Ai表示向第i户住户推销产品会积累的疲劳值。数据保证Ai<10^3。

    输出描述 Output Description

    输出N行,每行一个正整数,第i行整数表示当X=i时,阿明最多积累的疲劳值。

    样例输入 Sample Input

    【样例1】
    5
    1 2 3 4 5
    1 2 3 4 5

    【样例2】
    5
    1 2 2 4 5
    5 4 3 4 1

    样例输出 Sample Output

    【样例1】
    15
    19
    22
    24
    25

    【样例2】
    12
    17
    21
    24
    27

    数据范围及提示 Data Size & Hint

    1≤N≤100000
    注:请用 scanf 输入。

     
    【题解】
    根据线段树思想,先建立两棵线段树,一棵存距离*2+疲劳值,也就是s[i]*2+a[i],一棵存疲劳值,即a[i]。
    建树之后,先特判第一个,也就是第一棵树上最大的值直接输出来,将位置存在mx中。
    mx的作用是存每次处理之后已经取过的最远的点,也就是i最大的点。
    之后根据mx,在mx的左边寻找疲劳值最大的点,记为a1。在mx的右边寻找s[i]*2+a[i]最大的点,记为a2。
    因为a1是在mx的左边,所以如果取左边直接ans加上a1(最大疲劳值)就行了。但是因为a2在mx右边,所以如果取右边除了加上a2还要减去s[mx]*2,因为我们等于加了双重的s,即ans原=s[mx]*2+a[mx] , a2=max(s[i]*2+a[i])(mx<i<=n) , ans现=ans原+a2-s[mx]*2=s[mx]*2+a[mx]+max(s[i]*2+a[i])-s[mx]*2=a[mx]+max(s[i]*2+a[i])。
    那么如何判断左边还是右边更优呢?
    根据我们已经知道a1与a2在左/右边的区别,那么直接判断加完之后的数哪个大就好啦,即ans+a1 ?>(<) ans+a2-s[mx]*2。
    然后如果取右边的点,则要更新mx。
    还有一个点,就是mx-1<0,mx+1>n,a1=0,a2=0这几种情况要特别注意,写的时候记得加个特判。
    说道更新mx,就要记录最大点的所在位置,只要每棵树开一个p数组存位置就好啦。
    然后取过的点记得清零就好了。
    代码
    uses math;
    var n,i,j,ans,mx,a1,a2,pl1,pl2:longint;
    var a,sum,mn,p,sum1,mn1,p1,v,aa:array[0..400020] of longint;
    procedure up1(h:longint);
    begin
      sum[h]:=sum[h<<1]+sum[h<<1 or 1];
      mn[h]:=max(mn[h<<1],mn[h<<1 or 1]);
      if mn[h<<1]>mn[h<<1 or 1] then p[h]:=p[h<<1] else p[h]:=p[h<<1 or 1];
    end;
    procedure up2(h:longint);
    begin
      sum1[h]:=sum1[h<<1]+sum1[h<<1 or 1];
      mn1[h]:=max(mn1[h<<1],mn1[h<<1 or 1]);
      if mn1[h<<1]>mn1[h<<1 or 1] then p1[h]:=p1[h<<1] else p1[h]:=p1[h<<1 or 1];
    end;
    procedure build(h,l,r:longint);
    var m:longint;
    begin
      if l=r then begin sum[h]:=a[l];mn[h]:=a[l];p[h]:=l;
      sum1[h]:=aa[l];mn1[h]:=aa[l];p1[h]:=l;exit;end;
      m:=(l+r)>>1;build(h<<1,l,m);build(h<<1 or 1,m+1,r);up1(h);up2(h);
    end;
    procedure add1(h,c,l,r,x:longint);
    var m:longint;
    begin
      if (x<=l) and (x>=r) then begin
        inc(sum[h],c*(r-l+1));inc(mn[h],c);exit;end;
      m:=(l+r)>>1;
      if x<=m then add1(h<<1,c,l,m,x);
      if x>m then add1(h<<1 or 1,c,m+1,r,x);
      up1(h);
    end;
    procedure add2(h,c,l,r,x:longint);
    var m:longint;
    begin
      if (x<=l) and (x>=r) then begin
        inc(sum1[h],c*(r-l+1));inc(mn1[h],c);exit;end;
      m:=(l+r)>>1;
      if x<=m then add2(h<<1,c,l,m,x);
      if x>m then add2(h<<1 or 1,c,m+1,r,x);
      up2(h);
    end;
    function wm1(h,l,r,x,y:longint):longint;
    var m,ans,num:longint;
    begin
      if (x<=l) and (y>=r) then begin
      exit(mn[h]);end;
      m:=(l+r)>>1;ans:=-2147483647;
      if x<=m then
      begin
        num:=wm1(h<<1,l,m,x,y);
        if num>ans then begin ans:=num;pl1:=p[h<<1];end;
      end;
      if y>m then
      begin
        num:=wm1(h<<1 or 1,r+1,m,x,y);
        if num>ans then begin ans:=num;pl1:=p[h<<1 or 1];end;
      end;
      exit(ans);
    end;
    function wm2(h,l,r,x,y:longint):longint;
    var m,ans,num:longint;
    begin
      if (x<=l) and (y>=r) then begin
      exit(mn1[h]);end;
      m:=(l+r)>>1;ans:=-2147483647;
      if x<=m then
      begin
        num:=wm2(h<<1,l,m,x,y);
        if num>ans then begin ans:=num;pl2:=p1[h<<1];end;
      end;
      if y>m then
      begin
        num:=wm2(h<<1 or 1,r+1,m,x,y);
        if num>ans then begin ans:=num;pl2:=p1[h<<1 or 1];end;
      end; 
      exit(ans);
    end;
    begin
      read(n);for i:=1 to n do read(v[i]);
      for i:=1 to n do begin read(aa[i]);a[i]:=v[i]*2+aa[i];end;build(1,1,n);
      writeln(a[p[1]]);mx:=p[1];ans:=a[p[1]];
      add1(1,-a[mx],1,n,mx);add2(1,-aa[mx],1,n,mx);
      for i:=2 to n do
      begin
        a1:=wm2(1,1,n,1,mx-1);
        a2:=wm1(1,1,n,mx+1,n);
        if ((mx-1<0) or ((mx-1>0) and (mx+1<n) and (ans+a1>=ans+a2-v[mx]*2))
        or (a1=0)) and (a2<>0) then
        begin inc(ans,a2-v[mx]*2);mx:=pl1;end
        else begin inc(ans,a1);pl1:=pl2;end;
        writeln(ans);
        add1(1,-a[pl1],1,n,pl1);add2(1,-aa[pl1],1,n,pl1);
      end;
    end.
    

      

  • 相关阅读:
    java三大框架
    Servlet 工作原理解析
    Android四大基本组件介绍与生命周期
    wait 和 sleep
    Linux Mysql使用
    Android开发人员必备的10 个开发工具
    AIDL
    IPC Binder
    php 比较2字符串相似度 百分比
    php 数字 的简单加解密
  • 原文地址:https://www.cnblogs.com/ligen1353055672/p/7732849.html
Copyright © 2011-2022 走看看