嗯。。A掉了一道看起來很有技術水平的題。。
覺得挺開心的。。
Description - 問題描述
某校開展了同學們喜聞樂見的陽光長跑活動。爲了能“爲祖國健康工作五十年”,同學們紛紛離開寢室,離開教室,離開實驗室,到操場參加3000米長跑運動。一時間操場上熙熙攘攘,摩肩接踵,盛況空前。
爲了讓同學們更好地監督自己,學校推行了刷卡機制。
學校中有n個地點,用1到n的整數表示,每個地點設有若干個刷卡機,且兩個地點之間有跑道相連接。
問一個同學從A出發,最後到達B最多可以刷卡多少次。具體的要求如下:
當同學到達一個地點時,他可以在這裏的每一臺刷卡機上都刷卡。但每臺刷卡機只能刷卡一次,即使多次到達同一地點也不能多次刷卡。
爲了安全起見,每條跑道都需要設定一個方向(每次詢問相互獨立),這條跑道只能按照這個方向單向通行。最多的刷卡次數即爲在任意設定跑道方向,按照任意路徑從A地點到B地點能刷卡的最多次數。
Input - 輸入數據
第一行兩個整數n,m,q表示n個地點和m條跑道有q組詢問。
第二行n個數分別表示n個地點的刷卡機個數
然後m行每行兩個數a b表示a b兩地點之間有一條跑道
然後q行每行兩個數A B表示詢問從A到B的最多刷卡次數
Output - 輸出數據
Q行,每行一個數表示最多刷卡次數
Hint - 額外信息
樣例解釋:
詢問1 2,則按1->3->2跑,最多可刷6次;
詢問1 3,則按1->2->3跑,6次;
詢問2 3,則按2->1->3跑,6次。
30%的數據滿足n,m,q<=13
另20%的數據滿足m=n-1, n,m,q<=10^5
100%的數據滿足n,q<=10^5 m<=5*10^5
100%的數據滿足圖聯通,每個點得刷卡機數量不超過100
--------------------------
嗯剛開始做的時候以爲是強聯通分量[其實這是一個無向圖哪來的強聯通分量?],就一直WA
後來發現其實是邊-雙連通分量。。
求雙連通分量的方法這裏補充一下
首先求橋,橋的求法就是在dfs的時候,
如果對於一條邊,low[v]>dfn[u],那麼(u,v)就是橋
很好理解嘛。。就是Low[v]到不了v之上的,那麼把(u,v)去掉就會不連通了
而邊-雙連通分量很明顯就是整個圖除去橋之後的聯通分量。
這個也是挺好理解的嘛。。因爲除了橋之外,剩下的聯通分量裏的任意兩點之間肯定有多條不一樣的道路[如果只有一條,就會被當做橋處理掉嘛。。]
所以我們就可以求雙連通分量了
那麼總算是搞明白了。。
因爲如果要從一個點跑到另外一個點,那麼這兩個點一定要是在同一個邊-雙連通分量裏,這樣它就可以去再回來。。
那麼先雙連通分量縮點一下,,
得出來的肯定是一棵樹。。
然後對它統計LCA就可以
雙連通分量通常都伴隨着LCA
對了說下處理縮點之後的辦法
如何來判斷哪些邊雙連通分量是相連的呢?
最暴力的辦法是遍歷所有邊一遍。。
但明顯這太暴力了。。
我們可以在tarjan的時候存下橋
對於每一個橋,它肯定連接兩個邊雙連通分量,然後統計一下就可以了~
Code:
const shuru='running.in';
shuchu='running.out';
maxlen=14;
maxn=100001;
maxm=600001;
var b,deep,dfn,low,belong,a,head,headlist:Array[0..maxn] of longint;
sigh,too,nextt,t,next:Array[0..maxm] of longint;
hash:array[0..maxm] of boolean;
re1,re2:array[0..maxn] of longint;
vis,ins:Array[0..maxn] of boolean;
f,d:array[0..maxn,0..17] of longint;
mi:Array[0..17] of longint;
step,v,cnt,top,time,x,y,num,i,j,k,n,m,q:longint;
procedure init;
begin
readln(n,m,q);
fillchar(hash,sizeof(hash),true);
mi[0]:=1;
for i:=1 to 17 do mi[i]:=mi[i-1]*2;
for i:=1 to n do begin headlist[i]:=-1; head[i]:=-1; end;
for i:=1 to n do read(b[i]);
for i:=1 to m do
begin
readln(x,y);
inc(num);
next[num]:=headlist[x];
headlist[x]:=num;
t[num]:=y;
inc(num);
next[num]:=headlist[y];
headlist[y]:=num;
t[num]:=x;
sigh[num-1]:=num;
sigh[num]:=num-1;
end;
end;
function min(a,b:longint):longint;inline;
begin
if a<b then exit(a);
exit(b);
end;
procedure tarjan(u,fa:longint);
var i:longint;
begin
inc(time); dfn[u]:=time; low[u]:=time;
vis[u]:=true;
i:=headlist[u];
while i<>-1 do
begin
if not(vis[t[i]]) then begin
tarjan(t[i],u);
if low[t[i]]>dfn[u] then begin hash[i]:=false; hash[sigh[i]]:=false; inc(cnt); re1[cnt]:=u; re2[cnt]:=t[i]; end;
low[u]:=min(low[u],low[t[i]]);
end
else if t[i]<>fa then low[u]:=min(low[u],dfn[t[i]]);
i:=next[i];
end;
end;
procedure got(u:longint);
var i:longint;
begin
belong[u]:=time;
inc(a[time],b[u]);
vis[u]:=true;
i:=headlist[u];
while i<>-1 do
begin
if hash[i] then if not(vis[t[i]]) then got(t[i]);
i:=next[i];
end;
end;
procedure dfs(u:longint);
var i:longint;
begin
d[u,0]:=a[f[u,0]];
for i:=1 to maxlen do f[u,i]:=f[f[u,i-1],i-1];
for i:=1 to maxlen do d[u,i]:=d[u,i-1]+d[f[u,i-1],i-1];
vis[u]:=true;
i:=head[u];
while i<>-1 do
begin
if not(vis[too[i]]) then begin
deep[too[i]]:=deep[u]+1;
f[too[i],0]:=u;
dfs(too[i]);
end;
i:=nextt[i];
end;
end;
function ask(x,y:longint):longint;
var i,len:longint;
begin
if deep[x]>deep[y] then begin
step:=x;
x:=y;
y:=step;
end;
len:=deep[y]-deep[x];
if x=y then exit(a[x]);
ask:=a[x]+a[y];
for i:=0 to maxlen do
if ((len and mi[i])<>0) then begin
ask:=ask+d[y,i];
y:=f[y,i];
end;
if x<>y then begin
for i:=maxlen downto 0 do
if f[x,i]<>f[y,i] then begin
inc(ask,d[x,i]); inc(ask,d[y,i]);
x:=f[x,i]; y:=f[y,i];
end;
x:=f[x,0]; y:=f[y,0];
inc(ask,a[x]);
inc(ask,a[y]);
end;
dec(ask,a[x]);
end;
procedure main;
begin
init;
tarjan(1,0);
fillchar(vis,sizeof(vis),false);
time:=0;
num:=0;
for i:=1 to n do
if not(vis[i]) then begin
inc(time);
got(i);
end;
for i:=1 to cnt do
begin
inc(num);
nextt[num]:=head[belong[re1[i]]];
head[belong[re1[i]]]:=num;
too[num]:=belong[re2[i]];
inc(num);
nextt[num]:=head[belong[re2[i]]];
head[belong[re2[i]]]:=num;
too[num]:=belong[re1[i]];
end;
fillchar(vis,sizeof(vis),false);
dfs(belong[1]);
for i:=1 to q do
begin
readln(x,y);
writeln(ask(belong[x],belong[y]));
end;
end;
begin
main;
end.