某校開展了同學們喜聞樂見的陽光長跑活動。為了能「為祖國健康工作五十年」,同學們紛紛離開寢室,離開教室,離開實驗室,到操場參加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一邊使用並查集分別維護連通塊和邊雙連通分量 加邊時,若兩點不聯通,...