bzoj 1568 && bzoj 3165 超哥线段树

61 篇文章 0 订阅
7 篇文章 0 订阅

bzoj 1568

题意:插入多条射线(起点横坐标为1),以及询问某个x值能截到的最大纵坐标

超哥线段树...

这里蒟蒻不想说话...

推荐两篇博客:

http://blog.csdn.net/u012288458/article/details/51865920

http://www.cnblogs.com/DaD3zZ-Beyonder/p/5478433.html

注意:线段树根的区间范围是[1,50000],手欠习惯[1,n]了,结果操作数读入了个n覆盖了...mdzz

type
        rec=record
            k,b:double;
            flag:boolean;
end;

var
        n,x             :longint;
        i               :longint;
        ch              :char;
        s               :string;
        b,k,ans         :double;
        t               :array[0..200010] of rec;

function cross(k1,b1,k2,b2:double):double;
begin
   exit((b2-b1)/(k1-k2));
end;

function max(a,b:double):double;
begin
   if a>b then exit(a) else exit(b);
end;

procedure insert(x,l,r:longint;b,k:double);
var
        mid:longint;
        t1,t2,t3,t4,xx:double;
begin
   if not t[x].flag then
   begin
      t[x].flag:=true; t[x].k:=k; t[x].b:=b;
   end else
   begin
      mid:=(l+r)>>1;
      t1:=k*l+b; t2:=t[x].k*l+t[x].b;
      t3:=k*r+b; t4:=t[x].k*r+t[x].b;
      if (t1<=t2) and (t3<=t4) then exit;
      if (t1>=t2) and (t3>=t4) then
      begin
         t[x].k:=k; t[x].b:=b;
      end else
      begin
         xx:=cross(k,b,t[x].k,t[x].b);
         if (t1>=t2) then
         begin
            if xx<=mid then insert(2*x,l,mid,b,k) else
            begin
                insert(2*x+1,mid+1,r,t[x].b,t[x].k);
                t[x].k:=k; t[x].b:=b;
            end;
         end else
         begin
            if xx>mid then insert(2*x+1,mid+1,r,b,k) else
            begin
               insert(2*x,l,mid,t[x].b,t[x].k);
               t[x].k:=k; t[x].b:=b;
            end
         end;
      end;
   end;
end;

procedure find(x,l,r,y:longint);
var
        mid:longint;
begin
   if t[x].flag then ans:=max(ans,t[x].b+t[x].k*y);
   if l=r then exit;
   mid:=(l+r)>>1;
   if y<=mid then find(2*x,l,mid,y) else find(2*x+1,mid+1,r,y);
end;

begin
   readln(n);
   for i:=1 to n do
   begin
      read(ch);
      s:='';
      while ch<>' ' do
      begin
         s:=s+ch;
         read(ch);
      end;
      if s='Query' then
      begin
         readln(x);
         ans:=0;
         find(1,1,50000,x);
         writeln(trunc(ans/100));
      end else
      begin
         readln(b,k);
         insert(1,1,50000,b-k,k);
      end;
   end;
end.


bzoj 3165

题意:插入多条线段,第i条插入的线段编号为i,求某个x值能截到最大纵坐标的线段编号,如果多条线段符合要求,输出编号最小的

和上题类似,只不过这次维护的是线段并且是在满足纵坐标最大情况下的最小线段编号,所以维护的细节就多了一些:

(1)如果当前线段不能贯穿当前区间,直接下放给儿子

(2)如果当前区间没有被更新过,直接更新为当前线段

(3)如果当前线段与当前区间的最优相同且编号小于当前区间最优的线段,把当前区间更新为当前线段

(4)其他修改同上题

const
        mo=39989;
        eps=1e-6;
type
        rec=record
            l,r,id:longint;
            k,b:double;
            flag:boolean;
end;

var
        m,x,x1,x2,y1,y2 :longint;
        lastans,pos,tot :longint;
        op              :longint;
        ans,k,b         :double;
        i               :longint;
        t               :array[0..160010] of rec;

procedure swap(var a,b:longint);
var
        c:longint;
begin
   c:=a; a:=b; b:=c;
end;

function cross(k1,b1,k2,b2:double):double;
begin
   exit((b2-b1)/(k1-k2));
end;

procedure insert(x,tl,tr,l,r:longint;k,b:double;num:longint);
var
        mid:longint;
        t1,t2,t3,t4,xx:double;
begin
   if (l<=tl) and (r>=tr) then
   begin
      if not t[x].flag then
      begin
         t[x].flag:=true; t[x].k:=k; t[x].b:=b; t[x].id:=num; t[x].l:=l; t[x].r:=r
      end else
      begin
         t1:=k*tl+b; t2:=t[x].k*tl+t[x].b;
         t3:=k*tr+b; t4:=t[x].k*tr+t[x].b;
         mid:=(tl+tr)>>1;
         if (abs(t1-t2)<eps) and (abs(t3-t4)<eps) and (t[x].id>num) then
         begin
            t[x].k:=k; t[x].b:=b; t[x].id:=num; t[x].l:=l; t[x].r:=r;
         end else
         if (t1<=t2) and (t3<=t4) then exit else
         if (t1>=t2) and (t3>=t4) then
         begin
            t[x].k:=k; t[x].b:=b; t[x].id:=num; t[x].l:=l; t[x].r:=r;
         end else
         begin
            xx:=cross(k,b,t[x].k,t[x].b);
            if (t1>=t2) then
            begin
               if xx<=mid then insert(2*x,tl,mid,l,r,k,b,num) else
               begin
                  insert(2*x+1,mid+1,tr,t[x].l,t[x].r,t[x].k,t[x].b,t[x].id);
                  t[x].k:=k; t[x].b:=b; t[x].id:=num; t[x].l:=l; t[x].r:=r;
               end;
            end else
            begin
               if xx>mid then insert(2*x+1,mid+1,tr,l,r,k,b,num) else
               begin
                  insert(2*x,tl,mid,t[x].l,t[x].r,t[x].k,t[x].b,t[x].id);
                  t[x].k:=k; t[x].b:=b; t[x].id:=num; t[x].l:=l; t[x].r:=r;
               end;
            end;
         end;
      end;
   end else
   begin
      mid:=(tl+tr)>>1;
      if r<=mid then insert(2*x,tl,mid,l,r,k,b,num) else
        if l>mid then insert(2*x+1,mid+1,tr,l,r,k,b,num) else
        begin
           insert(2*x,tl,mid,l,r,k,b,num);
           insert(2*x+1,mid+1,tr,l,r,k,b,num);
        end;
   end;
end;

procedure find(x,l,r,y:longint);
var
        mid:longint;
begin
   if t[x].flag then
     if (t[x].k*y+t[x].b>ans) or ((abs(t[x].k*y+t[x].b-ans)<eps) and (t[x].id<pos)) then
     begin
        ans:=t[x].k*y+t[x].b; pos:=t[x].id;
     end;
   if l=r then exit;
   mid:=(l+r)>>1;
   if y<=mid then find(2*x,l,mid,y) else find(2*x+1,mid+1,r,y);
end;

begin
   read(m); tot:=0; lastans:=0;
   for i:=1 to m do
   begin
      read(op);
      if op=1 then
      begin
         read(x1,y1,x2,y2); inc(tot);
         x1:=(x1+lastans-1) mod mo+1;
         x2:=(x2+lastans-1) mod mo+1;
         y1:=(y1+lastans-1) mod 1000000000+1;
         y2:=(y2+lastans-1) mod 1000000000+1;
         if x1>x2 then
         begin
            swap(x1,x2); swap(y1,y2);
         end;
         if x1=x2 then
         begin
            k:=0;
            if y1>y2 then b:=y1 else b:=y2;
         end else
         begin
            k:=(y1-y2)/(x1-x2);
            b:=y2-k*x2;
         end;
         insert(1,1,mo,x1,x2,k,b,tot);
      end else
      begin
         read(x);
         x:=(x+lastans-1) mod mo+1;
         ans:=0; pos:=maxlongint;
         find(1,1,mo,x);
         if pos=maxlongint then pos:=0;
         lastans:=pos;
         writeln(pos);
      end;
   end;
end.
——by Eirlys


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值