日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

BZOJ 2959 长跑 (LCT、并查集)

發(fā)布時(shí)間:2025/3/15 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 BZOJ 2959 长跑 (LCT、并查集) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

題目鏈接

https://www.lydsy.com/JudgeOnline/problem.php?id=2959

題解

真是被這題搞得心態(tài)大崩……調(diào)了7個(gè)小時(shí)……然而并查集都能寫成\(O(n^2)\)的我還能怪誰(shuí)呢

顯然要把每個(gè)邊雙連通分量縮成點(diǎn),點(diǎn)權(quán)為邊雙連通分量?jī)?nèi)所有點(diǎn)點(diǎn)權(quán)和,然后答案就等于兩點(diǎn)路徑上點(diǎn)權(quán)和
現(xiàn)在需要用LCT維護(hù),就比較麻煩
大概是一邊LCT一邊使用并查集分別維護(hù)連通塊和邊雙連通分量
加邊時(shí),若兩點(diǎn)不聯(lián)通,則link, 然后在維護(hù)連通塊的并查集里并起來(lái)
若兩點(diǎn)聯(lián)通但不在同一邊雙中,則把這兩個(gè)點(diǎn)路徑上的所有邊雙縮到一起(其實(shí)就是“刪除點(diǎn)”),順便加入到邊雙連通分量的并查集中
這個(gè)可以通過(guò)把路徑的splay提取出來(lái)進(jìn)行DFS實(shí)現(xiàn),因?yàn)槊總€(gè)點(diǎn)只會(huì)被刪一次所以復(fù)雜度正確
但是這里由于縮點(diǎn),我們每次在lct中訪問父親的時(shí)候要求它樹上父親在并查集里的代表元素。。。所以很容易寫錯(cuò)
時(shí)間復(fù)雜度\(O(n\log n\alpha(n))\).

代碼

#include<cstdio> #include<cstdlib> #include<iostream> #include<cassert> #include<ctime> #define llong long long using namespace std;const int N = 1.5e5; struct SplayNode {int son[2],fa,sum,val,rev; } 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 ret = 0; char ch = getchar();while(ch < '0' || ch > '9') ch = getchar();while(ch >= '0' && ch <= '9') ret = (ret << 3) + (ret << 1) + ch - '0' , ch = getchar();return ret; }int findfa(int id,int u) {if(id==0){int i = u;while(u!=uf1[u]) {u = uf1[u];}while(uf1[i]!=u){int j = uf1[i]; uf1[i] = u; i = j;}}else{int i = u;while(u!=uf2[u]) {u = uf2[u];}while(uf2[i]!=u){int j = uf2[i]; uf2[i] = u; i = j;}}return u; }bool isroot(int u) {int uu = findfa(1,spl[u].fa); return spl[uu].son[0]!=u && spl[uu].son[1]!=u;} bool sondir(int u) {return u==spl[findfa(1,spl[u].fa)].son[1];}void pushup(int u) {spl[u].sum = spl[spl[u].son[0]].sum+spl[u].val+spl[spl[u].son[1]].sum; }void pushdown(int u) {int ls = spl[u].son[0],rs = spl[u].son[1];if(spl[u].rev){spl[u].rev = 0;if(ls){swap(spl[ls].son[0],spl[ls].son[1]);spl[ls].rev ^= 1;}if(rs){swap(spl[rs].son[0],spl[rs].son[1]);spl[rs].rev ^= 1;}} }void rotate(int u) {int x = findfa(1,spl[u].fa),y = findfa(1,spl[x].fa); bool dir = sondir(u)^1;if(!isroot(x)) {spl[y].son[sondir(x)] = u;}spl[u].fa = y;spl[x].son[dir^1] = spl[u].son[dir];if(spl[x].son[dir^1]) {spl[spl[x].son[dir^1]].fa = x;}spl[u].son[dir] = x; spl[x].fa = u;pushup(x); }void splaynode(int u) {int x = u,tp = 0,y;while(!isroot(x)) {tp++; stk[tp] = x; x = findfa(1,spl[x].fa);}pushdown(x);while(tp) {pushdown(stk[tp]); tp--;}while(!isroot(u)){x = findfa(1,spl[u].fa),y = findfa(1,spl[x].fa);if(!isroot(x)) {sondir(x)^sondir(u) ? rotate(u) : rotate(x);}rotate(u);}pushup(u); }void access(int u) {for(int i=0; u; i=u,u=findfa(1,spl[u].fa)){splaynode(u);spl[u].son[1] = i; pushup(u);} }void makeroot(int u) {access(u); splaynode(u);spl[u].rev ^= 1; swap(spl[u].son[0],spl[u].son[1]); }void link(int u,int v) {makeroot(u); spl[u].fa = v; }void dfs(int u,int u0) {uf2[u] = u0;pushdown(u);if(spl[u].son[0]) dfs(spl[u].son[0],u0);if(spl[u].son[1]) dfs(spl[u].son[1],u0); }int main() {scanf("%d%d",&n,&q);for(int i=1; i<=n; i++) uf1[i] = uf2[i] = i;for(int i=1; i<=n; i++) a[i] = read(),spl[i].val = spl[i].sum = a[i];while(q--){int opt; opt = read();if(opt==1){int u,v; u = read(),v = read();int uu = findfa(0,u),vv = findfa(0,v);if(uu!=vv){link(findfa(1,u),findfa(1,v));uf1[uu] = vv;}else{uu = findfa(1,u),vv = findfa(1,v);makeroot(uu); access(vv); splaynode(vv);spl[vv].val = spl[vv].sum;dfs(vv,vv);spl[vv].son[0] = 0;}}else if(opt==2){int u,x; u = read(),x = read(); int delta = x-a[u]; a[u] = x;int uu = findfa(1,u); splaynode(uu);spl[uu].val += delta; spl[uu].sum += delta;}else if(opt==3){int u,v; u = read(),v = read();int uu = findfa(1,u),vv = findfa(1,v);int uuu = findfa(0,uu),vvv = findfa(0,vv);if(uuu!=vvv) {puts("-1"); continue;}else{makeroot(uu); access(vv); splaynode(vv);printf("%d\n",spl[vv].sum);}}}return 0; }

總結(jié)

以上是生活随笔為你收集整理的BZOJ 2959 长跑 (LCT、并查集)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。