真是被這題搞得心態大崩……調了7個小時……然而並查集都能寫成\(o(n^2)\)的我還能怪誰呢
顯然要把每個邊雙連通分量縮成點,點權為邊雙連通分量內所有點點權和,然後答案就等於兩點路徑上點權和
現在需要用lct維護,就比較麻煩
大概是一邊lct一邊使用並查集分別維護連通塊和邊雙連通分量
加邊時,若兩點不聯通,則link
, 然後在維護連通塊的並查集裡並起來
若兩點聯通但不在同一邊雙中,則把這兩個點路徑上的所有邊雙縮到一起(其實就是「刪除點」),順便加入到邊雙連通分量的並查集中
這個可以通過把路徑的splay提取出來進行dfs實現,因為每個點只會被刪一次所以複雜度正確
但是這裡由於縮點,我們每次在lct中訪問父親的時候要求它樹上父親在並查集裡的代表元素。。。所以很容易寫錯
時間複雜度\(o(n\log n\alpha(n))\).
#include#include#include#include#include#define llong long long
using namespace std;
const int n = 1.5e5;
struct splaynode
spl[n+3];
int uf1[n+3],uf2[n+3];
int stk[n+3];
int a[n+3];
int n,q;
inline int read()
int findfa(int id,int u)
while(uf1[i]!=u)
}else
while(uf2[i]!=u)
}return u;
}bool isroot(int u)
bool sondir(int u)
void pushup(int u)
void pushdown(int u)
if(rs)
}}void rotate(int u)
spl[u].fa = y;
spl[x].son[dir^1] = spl[u].son[dir];
if(spl[x].son[dir^1])
spl[u].son[dir] = x; spl[x].fa = u;
pushup(x);
}void splaynode(int u)
pushdown(x);
while(tp)
while(!isroot(u))
rotate(u);
}pushup(u);
}void access(int u)
}void makeroot(int u)
void link(int u,int v)
void dfs(int u,int u0)
int main()
else
}else if(opt==2)
else if(opt==3)
else}}
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...
bzoj2959 長跑 LCT 並查集
某校開展了同學們喜聞樂見的陽光長跑活動。為了能 為祖國健康工作五十年 同學們紛紛離開寢室,離開教室,離開實驗室,到操場參加3000公尺長跑運動。一時間操場上熙熙攘攘,摩肩接踵,盛況空前。為了讓同學們更好地監督自己,學校推行了刷卡機制。學校中有n個地點,用1到n的整數表示,每個地點設有若干個刷卡機。有...