bzoj2959 長跑 LCT 並查集

2021-08-13 02:33:08 字數 2627 閱讀 3689

某校開展了同學們喜聞樂見的陽光長跑活動。為了能「為祖國健康工作五十年」,同學們紛紛離開寢室,離開教室,離開實驗室,到操場參加3000公尺長跑運動。一時間操場上熙熙攘攘,摩肩接踵,盛況空前。

為了讓同學們更好地監督自己,學校推行了刷卡機制。

學校中有n個地點,用1到n的整數表示,每個地點設有若干個刷卡機。

有以下三類事件:

1、修建了一條連線a地點和b地點的跑道。

2、a點的刷卡機台數變為了b。

3、進行了一次長跑。問乙個同學從a出發,最後到達b最多可以刷卡多少次。具體的要求如下:

當同學到達乙個地點時,他可以在這裡的每一台刷卡機上都刷卡。但每台刷卡機只能刷卡一次,即使多次到達同一地點也不能多次刷卡。

為了安全起見,每條跑道都需要設定乙個方向,這條跑道只能按照這個方向單向通行。最多的刷卡次數即為在任意設定跑道方向,按照任意路徑從a地點到b地點能刷卡的最多次數。

輸入的第一行包含兩個正整數n,m,表示地點的個數和操作的個數。

第二行包含n個非負整數,其中第i個數為第個地點最開始刷卡機的台數。

接下來有m行,每行包含三個非負整數p,a,b,p為事件型別,a,b為事件的兩個引數。

最初所有地點之間都沒有跑道。

每行相鄰的兩個數之間均用乙個空格隔開。表示地點編號的數均在1到n之間,每個地點的刷卡機台數始終不超過10000,p=1,2,3。

輸出的行數等於第3類事件的個數,每行表示乙個第3類事件。如果該情況下存在一種設定跑道方向的方案和路徑的方案,可以到達,則輸出最多可以刷卡的次數。如果a不能到達b,則輸出-1。

碼了一整個下午,終於過了樣例,結果ac了……這題樣例好強大。。

題解:

「為了安全起見,每條跑道都需要設定乙個方向,這條跑道只能按照這個方向單向通行。最多的刷卡次數即為在任意設定跑道方向,按照任意路徑從a地點到b地點能刷卡的最多次數。」這句話是關鍵。因此,路途中經過的任意乙個強聯通分量的所有點權之和要全部加上。於是我們就動態維護強聯通分量。開2個並查集,乙個儲存的是原樹之間的關係用來判斷連通性,乙個儲存的是強聯通分量的代表節點。至於為什麼要用第乙個並查集,原因是…加速。於是每連一條邊u-v,就用第乙個並查集判斷一下u,v是否連通。如果沒有,就直接連線,否則意味著圖中出現了乙個環。於是,我們把這個環上的所有節點(也就是原來u-v的路徑上的所有點)的點權移到乙個代表節點上,然後丟掉其他所有點,還要把所有點的第二個並查集的父親賦值為代表節點,因為它們屬於的強聯同分量改變了。怎麼刪除不要的點呢?只要保證不會在各種操作的時候跳到不要的節點即可。具體實現時,只要把所有的fa改為find(fa)即可,就會跳到代表節點上。剩下兩個操作都是經典操作。不知道有沒有什麼更快的方法,但可以肯定的是,我的**常數巨大==

**:

#include

#include

using

namespace

std;

const

int n=150005;

int n,m,op,u,v,fu0,fv0,fu1,fv1,pa[n][2],fa[n],ch[n][2],rev[n],val[n],sumv[n];

int a[n],stk[n];

int find(int u,int md)

bool isroot(int u)

int tmp=find(fa[u],1);

return u!=ch[tmp][0]&&u!=ch[tmp][1];

}int which(int u)

void pushup(int u)

sumv[u]=val[u]+sumv[ch[u][0]]+sumv[ch[u][1]];

}void reverse(int u)

void downtag(int u)

if(ch[u][1])

rev[u]=0;

}}void pushdown(int u)

while(stk[0])

}void rotate(int x)

fa[x]=z;

ch[y][md]=ch[x][!md];

if(ch[y][md])

ch[x][!md]=y;

if(y)

pushup(y);

pushup(x);

}void splay(int u)

rotate(u);

}}void access(int u)

}void makeroot(int u)

int dfs(int rt,int u)

pa[u][1]=rt;

return dfs(rt,ch[u][0])+dfs(rt,ch[u][1])+val[u];

}int main()

for(int i=1;i<=n;i++)

for(int i=1;i<=m;i++)else

}}else

if(op==2)else

fu1=find(u,1),fv1=find(v,1);

makeroot(fu1);

access(fv1);

splay(fv1);

printf("%d\n",sumv[fv1]);}}

return

0;}

bzoj 2959 長跑(LCT 並查集)

time limit 10 sec memory limit 256 mb submit 315 solved 178 submit status discuss 某校開展了同學們喜聞樂見的陽光長跑活動。為了能 為祖國健康工作五十年 同學們紛紛離開寢室,離開教室,離開實驗室,到操場參加3000公尺長...

BZOJ2959 長跑(lct 並查集)

傳送門 用lct維護一顆動態樹。如果連了某一條邊形成了乙個環,證明一次長跑這個環上的所有的點都可以被統計,所以可以將這個環縮成乙個點。用ufs來實現。那麼一次長跑實際上就是在一條樹鏈上跑,只有乙個方向,在lct上維護乙個sum就可以了。時間複雜度是均攤的,因為每乙個點至多被縮點一次,所以o k ml...

BZOJ 2959 長跑 LCT 並查集

真是被這題搞得心態大崩 調了7個小時 然而並查集都能寫成 o n 2 的我還能怪誰呢 顯然要把每個邊雙連通分量縮成點,點權為邊雙連通分量內所有點點權和,然後答案就等於兩點路徑上點權和 現在需要用lct維護,就比較麻煩 大概是一邊lct一邊使用並查集分別維護連通塊和邊雙連通分量 加邊時,若兩點不聯通,...