[YZOI 2089] 邊雙連通分量和橋

嗯。。A掉了一道看起來很有技術水平的題。。

覺得挺開心的。。

2089:跑步(running)  Accept

 

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行,每行一個數表示最多刷卡次數

 

Input/Output Example - 輸入/輸出樣例

點擊藍色按鈕可複製數據
3 3 3
1 2 3
1 2
1 3
2 3
1 2
1 3
2 3
 

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.


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章