您的位置:首页 > 其它

bzoj2791

2015-06-04 19:44 134 查看
每个顶点有且仅有一条出边是什么意思呢

类似一棵树,树上的边都是由儿子指向父亲的,并且这个东西带着一个环

也就是一个个有向环套有向树……

这题还是比较简单的,把环作为根然后类似lca做即可,注意细节的panding

type node=record
po,next:longint;
end;

var e:array[0..500010] of node;
s,p,w,c,be,d,q:array[0..500010] of longint;
v:array[0..500010] of boolean;
anc:array[0..500010,0..20] of longint;
t,f,r,n,m,len,i,x,y,a,b:longint;

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

function min(a,b:longint):longint;
begin
if a>b then exit(b) else exit(a);
end;

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

procedure add(x,y:longint);
begin
inc(len);
e[len].po:=y;
e[len].next:=p[x];
p[x]:=len;
end;

procedure bfs;
var x,i,y:longint;
begin
f:=1;
while f<=r do
begin
x:=q[f];
for i:=1 to 20 do
begin
y:=anc[x,i-1];
if y<>0 then anc[x,i]:=anc[y,i-1] else break;
end;
i:=p[x];
while i<>0 do
begin
y:=e[i].po;
if not v[y] then
begin
d[y]:=d[x]+1;
anc[y,0]:=x;
be[y]:=t;
inc(r);
q[r]:=y;
v[y]:=true;
end;
i:=e[i].next;
end;
inc(f);
end;
end;

procedure lca(x,y:longint);
var i,num,a1,b1,a2,b2:longint;
begin
a:=0; b:=0;
if d[x]>d[y] then
for i:=20 downto 0 do
if d[x]-1 shl i>=d[y] then
begin
x:=anc[x,i];
a:=a+1 shl i;
end;

if d[y]>d[x] then
for i:=20 downto 0 do
if d[y]-1 shl i>=d[x] then
begin
y:=anc[y,i];
b:=b+1 shl i;
end;

if x=y then exit;
for i:=20 downto 0 do
if (anc[x,i]<>anc[y,i]) then
begin
x:=anc[x,i]; a:=a+1 shl i;
y:=anc[y,i]; b:=b+1 shl i;
end;

if (anc[x,0]=anc[y,0]) and (anc[x,0]<>0) then
begin
inc(a); inc(b);
exit;
end;
num:=s[be[x]];
if c[x]>c[y] then a1:=a+num-c[x]+c[y] else a1:=a+c[y]-c[x];
b1:=b;
a2:=a;
if c[x]<c[y] then b2:=b+num-c[y]+c[x] else b2:=b+c[x]-c[y];
if max(a1,b1)=max(a2,b2) then
begin
if (min(a1,b1)>min(a2,b2)) or (min(a1,b1)=min(a2,b2)) and (a1<b1) then
begin
a:=a2;
b:=b2;
end
else begin
a:=a1;
b:=b1;
end;
end
else if max(a1,b1)>max(a2,b2) then
begin
a:=a2;
b:=b2;
end
else begin
a:=a1;
b:=b1;
end;
end;

begin
readln(n,m);
for i:=1 to n do
begin
read(w[i]);
add(w[i],i);
end;

for i:=1 to n do
if be[i]=0 then
begin
inc(t);
be[i]:=t;
x:=i;
while true do
begin
x:=w[x];
if be[x]=t then break;
be[x]:=t;
end;
y:=x;
r:=0;
repeat
inc(s[t]);
c[y]:=s[t];
inc(r);
q[r]:=y;
v[y]:=true;
y:=w[y];
until y=x;
bfs;
end;

for i:=1 to m do
begin
readln(x,y);
if be[x]<>be[y] then
begin
writeln('-1 -1');
continue;
end;
lca(x,y);
writeln(a,' ',b);
end;
end.


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