您的位置:首页 > 其它

[BZOJ3991] [SDOI2015]寻宝游戏

2016-03-06 13:57 260 查看

传送门

http://www.lydsy.com/JudgeOnline/problem.php?id=3991

题目大意

给定一棵树,询问从某一关键点出发再回到该点遍历所有关键点的最短距离

支持加入1个和删除1个关键点

题解

首先最短路径一定是按照DFS序走

所以就动态维护关键点的DFS序就好了

(c++能用set!!我只好写了个SplayQAQAQAQ)

{$M 100000000,0,100000000}
const
maxn=100050;
inf=100000000000000;
var
w:array[0..3*maxn,1..3]of longint;
dd,pos,vis:array[-1..maxn]of longint;
dep:array[-1..maxn]of int64;
son:array[-1..maxn,1..2]of longint;
fa,val:array[-1..maxn]of longint;
st:array[0..maxn,0..20]of longint;
i,j,k:longint;
n,m,len,a,b,c,root:longint;
ans:int64;
procedure init(a,b,c:longint);
begin
w[len,1]:=b; w[len,2]:=c; w[len,3]:=0;
if (w[a,3]=0) then w[a,3]:=len else w[w[a,1],3]:=len;
w[a,1]:=len; inc(len);
end;

procedure dfs(a,fa:longint);
var tt:longint;
begin
tt:=w[a,3]; inc(len); pos[a]:=len;
while (tt<>0) do
begin
if (w[tt,1]<>fa) then
begin
dep[w[tt,1]]:=dep[a]+int64(w[tt,2]);
dd[w[tt,1]]:=dd[a]+1;
st[w[tt,1],0]:=a;
dfs(w[tt,1],a);
end;
tt:=w[tt,3];
end;
end;

function lca(a,b:longint):longint;
var i:longint;
begin
if (dd[a]<dd[b]) then begin i:=a; a:=b; b:=i; end;
for i:=20 downto 0 do
if (dd[st[a,i]]>=dd[b]) then a:=st[a,i];
if (a=b) then exit(a);
for i:=20 downto 0 do
if (st[a,i]<>st[b,i]) then begin a:=st[a,i]; b:=st[b,i]; end;
exit(st[a,0]);
end;

function dis(a,b:longint):int64;
begin
exit(dep[a]+dep[b]-2*dep[lca(a,b)]);
end;

procedure rotate(a,kind:longint);
var b,c,unkind:longint;
begin
b:=fa[a]; c:=fa[b]; unkind:=kind xor 3;
fa[son[a,unkind]]:=b; fa[b]:=a;
son[b,kind]:=son[a,unkind]; son[a,unkind]:=b;
fa[a]:=c;
if (son[c,1]=b)
then son[c,1]:=a
else son[c,2]:=a;
end;

procedure splay(a,goal:longint);
var kind,unkind,b:longint;
begin
while (fa[a]<>goal) do
begin
b:=fa[a]; if (son[b,1]=a) then kind:=1 else kind:=2; unkind:=kind xor 3;
if (fa[b]=goal) then rotate(a,kind)
else
if (son[fa[b],kind]=b)
then begin rotate(b,kind); rotate(a,kind); end
else begin rotate(a,kind); rotate(a,unkind); end;
end;
if (goal=-1) then root:=a;
end;

procedure insert(a:longint);
var tt,fath,kind:longint;
begin
tt:=root;
while (tt<>-1) do
if (pos[a]<pos[val[tt]])
then begin fath:=tt; kind:=1; tt:=son[tt,1]; end
else begin fath:=tt; kind:=2; tt:=son[tt,2]; end;
inc(len); son[len,1]:=-1; son[len,2]:=-1; fa[len]:=fath; val[len]:=a; son[fath,kind]:=len;
splay(len,-1);
end;

procedure delete(a:longint);
var tt:longint;
begin
tt:=root;
while (val[tt]<>a) do
if (pos[a]<pos[val[tt]])
then tt:=son[tt,1]
else tt:=son[tt,2];
splay(tt,-1);
tt:=son[root,1];
while (son[tt,2]<>-1) do
tt:=son[tt,2];
splay(tt,root);
son[tt,2]:=son[root,2]; root:=tt; fa[son[root,2]]:=tt; fa[root]:=-1;
end;

function getpre(a:longint):longint;
var tt:longint;
begin
tt:=root;
while (val[tt]<>a) do
if (pos[a]<pos[val[tt]])
then tt:=son[tt,1]
else tt:=son[tt,2];
splay(tt,-1);
splay(1,root);
if (son[1,2]=-1) then begin splay(2,-1); splay(1,root); end;
tt:=son[son[root,1],2];
while (son[tt,2]<>-1) do
tt:=son[tt,2];
exit(val[tt]);
end;

function getsuf(a:longint):longint;
var tt:longint;
begin
tt:=root;
while (val[tt]<>a) do
if (pos[a]<pos[val[tt]])
then tt:=son[tt,1]
else tt:=son[tt,2];
splay(tt,-1);
splay(2,root);
if (son[2,1]=-1) then begin splay(1,-1); splay(2,root); end;
tt:=son[son[root,2],1];
while (son[tt,1]<>-1) do
tt:=son[tt,1];
exit(val[tt]);
end;

begin
readln(n,m); len:=n+1;
for i:=1 to n-1 do
begin readln(a,b,c); init(a,b,c); init(b,a,c); end;
dep[1]:=1; dd[1]:=1; st[1,0]:=0; len:=0; dfs(1,0);
for j:=1 to 20 do
for i:=1 to n do
st[i,j]:=st[st[i,j-1],j-1];
fillchar(vis,sizeof(vis),0);
ans:=0; pos[-1]:=-maxlongint; pos[maxn]:=maxlongint;
len:=2; root:=1;
son[1,1]:=-1; son[1,2]:=2; fa[1]:=-1; val[1]:=-1;
son[2,1]:=-1; son[2,2]:=-1; fa[2]:=1; val[2]:=maxn;
for i:=1 to m do
begin
readln(a);
if (vis[a]=0) then
begin
vis[a]:=1; insert(a);
b:=getpre(a); c:=getsuf(a);
ans:=ans-dis(b,c)+dis(a,b)+dis(a,c);
end
else
begin
vis[a]:=0;
b:=getpre(a); c:=getsuf(a);
ans:=ans-dis(a,b)-dis(a,c)+dis(b,c);
delete(a);
end;
writeln(ans);
end;
end.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: