您的位置:首页 > 运维架构

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

2017-03-04 11:24 253 查看
又到了涨姿势的时候了



切比雪夫距离: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[
f53c
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



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  bzoj