bzoj 3170 计算几何 && bzoj 1604 计算几何+SBT维护

61 篇文章 0 订阅
3 篇文章 0 订阅

又到了涨姿势的时候了

切比雪夫距离:max{|x1-x2|,|y1-y2|}

欧几里得距离:sqrt(sqr(x1-x2)+ sqr(y1-y2))

曼哈顿距离:|x1-x2|+|y1-y2|

曼哈顿距离转化成切比雪夫距离:(x,y) -> (x+y,x-y),这样新点的切比雪夫距离就是原点的曼哈顿距离

切比雪夫距离转化成曼哈顿距离:(x,y)->  ((x+y)/2, (x-y)/2) ,这样新点的曼哈顿距离就是原点的切比雪夫距离(一般这样转化的时候为了避免double,都是在最终答案除以2)

相关过程证明见此神犇博客:http://blog.csdn.net/slongle_amazing/article/details/50911504

======================我才不告诉你我是分界线呢================================

bzoj 3170

题意:n个点,求n个点中的一个点到其余各点的切比雪夫距离和最小

那么我们把切比雪夫距离转化成了曼哈顿距离,即 |x1-x2|+|y1-y2| 的形式

那么我们分别求x轴和y轴的答案,累加判断即可

由于有绝对值,所以我们要先分别对横纵坐标排序

locx[i]表示原来第i个松鼠的横坐标排序后的相对位置,locy[i]同理

然后利用前缀和后缀和更新距离:

ansx = x[locx[i]]*(locx[i]-1) - sigma(x[j]) (1<=j<=locx[i]-1) + sigma(x[j]) (1<=j<=locx[i]+1)  - (n-locx[i]) -x[locx[i]]*(n-locx[i])

ansy = y[locy[i]]*(locy[i]-1) - sigma(y[j]) (1<=j<=locy[i]-1) + sigma(y[j]) (1<=j<=locy[i]+1)  - (n-locy[i]) -x[locy[i]]*(n-locy[i])

type
        rec=record
            pos,id:longint;
end;

var
        tt,ans          :qword;
        n,xx,yy         :longint;
        i               :longint;
        x,y             :array[0..100010] of rec;
        locx,locy       :array[0..100010] of longint;
        sumx1,sumx2     :array[0..100010] of int64;
        sumy1,sumy2     :array[0..100010] of int64;
procedure sort1(l,r:longint);
var
        i,j,a:longint;
        b:rec;
begin
   i:=l; j:=r; a:=x[(l+r)>>1].pos;
   while (i<=j) do
   begin
      while x[i].pos<a do inc(i);
      while x[j].pos>a do dec(j);
      if (i<=j) then
      begin
         b:=x[i]; x[i]:=x[j]; x[j]:=b;
         inc(i); dec(j);
      end;
   end;
   if i<r then sort1(i,r);
   if j>l then sort1(l,j);
end;

procedure sort2(l,r:longint);
var
        i,j,a:longint;
        b:rec;
begin
   i:=l; j:=r; a:=y[(l+r)>>1].pos;
   while (i<=j) do
   begin
      while y[i].pos<a do inc(i);
      while y[j].pos>a do dec(j);
      if (i<=j) then
      begin
         b:=y[i]; y[i]:=y[j]; y[j]:=b;
         inc(i); dec(j);
      end;
   end;
   if i<r then sort2(i,r);
   if j>l then sort2(l,j);
end;

begin
   read(n);
   for i:=1 to n do
   begin
      read(xx,yy);
      x[i].pos:=xx+yy; y[i].pos:=xx-yy;
      x[i].id:=i; y[i].id:=i;
   end;
   sort1(1,n);
   sort2(1,n);
   //
   for i:=1 to n do
   begin
      locx[x[i].id]:=i; locy[y[i].id]:=i;
      sumx1[i]:=sumx1[i-1]+int64(x[i].pos);
      sumy1[i]:=sumy1[i-1]+int64(y[i].pos);
   end;
   for i:=n downto 1 do
   begin
      sumx2[i]:=sumx2[i+1]+int64(x[i].pos);
      sumy2[i]:=sumy2[i+1]+int64(y[i].pos);
   end;
   //
   ans:=1<<62;
   for i:=1 to n do
   begin
      tt:=0;
      tt:=-sumx1[locx[i]-1]+int64(locx[i]-1)*x[locx[i]].pos+sumx2[locx[i]+1]-int64(n-locx[i])*x[locx[i]].pos;
      tt:=tt-sumy1[locy[i]-1]+int64(locy[i]-1)*y[locy[i]].pos+sumy2[locy[i]+1]-int64(n-locy[i])*y[locy[i]].pos;
      if tt<ans then ans:=tt;
   end;
   writeln(ans div 2);
end.


bzoj 1604

题意:n个点,给出一个定长m,如果两个点的曼哈顿距离不超过m则和两个点在一个群里,问最后会形成多少群,同时询问最大的群中最多包含几个点

考虑能否把横纵坐标通过一种转化可以分开考虑,如果可以的话我们的难度会下降很多。

题目要求在同一个群的条件是曼哈顿距离不超过m,而切比雪夫距离恰好是横纵坐标差的绝对值取max,貌似形式很像?

我们把曼哈顿距离转化成切比雪夫距离,这样两个点在同一个群的条件就变成了max{|xi-xj|,|yi-yj|}<=m,也就是说,只要我们保证|xi-xj|<=m 且 |yi-yj|<=m 

这样,我们成功的完成了我们的本愿,只需要分别验证两个条件是否同时满足即可

很显然,并查集维护群的关系和群的大小,由于很简单,不再赘述

对于新加入的i,我们找到满足|xi-xj|<=m 的点集,最可能满足第二个条件的点一定是这些点里纵坐标和yi差距最小的(即纵坐标是yi的前驱和后继),判断i是否和这两个点满足群的限制,如果满足就并查集合并,如果不满足就不会有其他的点会满足第二个条件(显然)

所以,我们先按照x坐标排序,然后用队来维护使队首到队尾的点满足|xi-xj|<=m(只要满足新点减队首的横坐标不超过m那么这之间的肯定也不超m),并把队首到队尾的点都放到平衡树里(不在队首到队尾范围内的从平衡树里删除),然后找到新点纵坐标的前驱和后继,判断能否合并,再把新点同时加到队列和平衡树里

注意当头指针移动时对应的平衡树里的点也要删除

type
        rec=record
            x,y,id:longint;
end;

var
        n,m,xx,yy,tot,t :longint;
        maxn,ans        :longint;
        i               :longint;
        father,num      :array[0..100010] of longint;
        a               :array[0..100010] of rec;
        l,r,size        :array[0..100010] of longint;
        key             :array[0..100010] of rec;

function get_father(x:longint):longint;
begin
   if x=father[x] then exit(x);
   father[x]:=get_father(father[x]);
   exit(father[x]);
end;

procedure sort(l,r:longint);
var
        i,j,x:longint;
        y:rec;
begin
   i:=l; j:=r; x:=a[(l+r)>>1].x;
   while (i<=j) do
   begin
      while a[i].x<x do inc(i);
      while a[j].x>x do dec(j);
      if (i<=j) then
      begin
         y:=a[i]; a[i]:=a[j]; a[j]:=y;
         inc(i); dec(j);
      end;
   end;
   if i<r then sort(i,r);
   if j>l then sort(l,j);
end;

procedure l_ro(var t:longint);
var
        k:longint;
begin
   k:=r[t];
   r[t]:=l[k];
   l[k]:=t;
   size[k]:=size[t];
   size[t]:=size[l[t]]+size[r[t]]+1;
   t:=k;
end;

procedure r_ro(var t:longint);
var
        k:longint;
begin
   k:=l[t];
   l[t]:=r[k];
   r[k]:=t;
   size[k]:=size[t];
   size[t]:=size[l[t]]+size[r[t]]+1;
   t:=k;
end;

procedure maintain(var t:longint;f:boolean);
begin
   if not f then
   begin
      if size[l[l[t]]]>size[r[t]] then r_ro(t) else
        if size[r[l[t]]]>size[r[t]] then
        begin
           l_ro(l[t]);
           r_ro(t);
        end else exit;
   end else
   begin
      if size[r[r[t]]]>size[l[t]] then l_ro(t) else
        if size[l[r[t]]]>size[l[t]] then
        begin
           r_ro(r[t]);
           l_ro(t);
        end else exit;
   end;
   maintain(l[t],false);
   maintain(r[t],true);
   maintain(t,true);
   maintain(t,false);
end;

procedure insert(var t:longint;v:rec);
begin
   if t=0 then
   begin
      inc(tot);
      t:=tot;
      l[t]:=0;
      r[t]:=0;
      size[t]:=1;
      key[t]:=v;
   end else
   begin
      inc(size[t]);
      if v.y<key[t].y then insert(l[t],v) else insert(r[t],v);
      maintain(t,v.y>=key[t].y);
   end;
end;

function succ(var t:longint;v:rec):rec;
begin
   if t=0 then exit(a[0]);
   if v.y=key[t].y then succ:=key[t];
   if v.y>key[t].y then succ:=succ(r[t],v) else
   begin
      succ:=succ(l[t],v);
      if succ.id=a[0].id then succ:=key[t];
   end;
end;

function pred(var t:longint;v:rec):rec;
begin
   if t=0 then exit(a[0]);
   if v.y=key[t].y then pred:=key[t];
   if v.y<key[t].y then pred:=pred(l[t],v) else
   begin
      pred:=pred(r[t],v);
      if pred.id=a[0].id then pred:=key[t];
   end;
end;

procedure connect(x,y:longint);
begin
   x:=get_father(x);
   y:=get_father(y);
   if (x<>y) then
   begin
      father[y]:=x;
      dec(ans);
      inc(num[x],num[y]);
      if num[x]>maxn then maxn:=num[x];
   end;
end;

function delete(var t:longint;v:longint):rec;
begin
   dec(size[t]);
   if (v=key[t].y) or (v>key[t].y) and (r[t]=0) or (v<key[t].y) and (l[t]=0) then
   begin
      delete:=key[t];
      if (l[t]=0) or (r[t]=0) then t:=l[t]+r[t]
        else key[t]:=delete(l[t],v+1);
   end else
   if v>key[t].y then delete:=delete(r[t],v) else delete:=delete(l[t],v);
end;

procedure find;
var
        i,now:longint;
        t1,t2:rec;
begin
   now:=1; insert(t,a[1]);
   for i:=2 to n do
   begin
      while (a[i].x-a[now].x>m) and (now<i) do
      begin
         delete(t,a[now].y);
         inc(now);
      end;
      if now<i then
      begin
         t1:=succ(t,a[i]);
         t2:=pred(t,a[i]);
         if (t1.y-a[i].y<=m) and (t1.id<>a[0].id) then connect(t1.id,a[i].id);
         if (a[i].y-t2.y<=m) and (t2.id<>a[0].id) then connect(t2.id,a[i].id);
      end;
      insert(t,a[i]);
   end;
end;

begin
   read(n,m); ans:=n; maxn:=1;
   for i:=1 to n do father[i]:=i;
   for i:=1 to n do num[i]:=1;
   a[0].id:=0;
   for i:=1 to n do
   begin
      read(xx,yy);
      a[i].x:=xx+yy; a[i].y:=xx-yy; a[i].id:=i;
   end;
   sort(1,n);
   find;
   writeln(ans,' ',maxn);
end.
——by Eirlys



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值