[動態最小生成樹 CDQ分治 Kruscal] BZOJ 2001 [Hnoi2010]City 城市建設
#include<cstdio> #include<cstdlib> #include<algorithm> using namespace std; typedef pair<int,int> abcd; typedef long long ll; inline char nc() { static char buf[100000],*p1=buf,*p2=buf; if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; } return *p1++; } inline void read(int &x) { char c=nc(),b=1; for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1; for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b; } const int oo=1<<30; const int N=50005; int n,m; struct edge{ int u,v,w,pos; bool operator < (const edge &B) const{ return w<B.w; } }e[25][N],d[N],t[N]; int c[N]; int a[N]; int fat[N],rank[N]; inline void init(edge *d,int n){ for (int i=1;i<=n;i++) fat[d[i].u]=d[i].u,fat[d[i].v]=d[i].v,rank[d[i].u]=rank[d[i].v]=0; } inline int Fat(int u){ return u==fat[u]?u:fat[u]=Fat(fat[u]); } inline bool Union(int x,int y){ x=Fat(x),y=Fat(y); if (x==y) return 0; if (rank[x]>rank[y]) swap(x,y); if (rank[x]==rank[y]) rank[y]++; fat[x]=y; return 1; } abcd q[N]; int Q; ll ans[N]; inline ll contraction(int &eds){ int tmp=0; ll tsum=0; init(d,eds); sort(d+1,d+eds+1); for (int i=1;i<=eds;i++) if (Union(d[i].u,d[i].v)) t[++tmp]=d[i]; init(d,eds); for (int i=1;i<=tmp;i++) if (t[i].w!=-oo && Union(t[i].u,t[i].v)) tsum+=t[i].w; tmp=0; for (int i=1;i<=eds;i++) if (Fat(d[i].u)!=Fat(d[i].v)) { t[++tmp]=d[i]; t[tmp].u=Fat(t[tmp].u); t[tmp].v=Fat(t[tmp].v); c[t[tmp].pos]=tmp; } for (int i=1;i<=tmp;i++) d[i]=t[i]; eds=tmp; return tsum; } inline void reduce(int &eds) { int tmp=0; init(d,eds); sort(d+1,d+eds+1); for (int i=1;i<=eds;i++) if (Union(d[i].u,d[i].v) || d[i].w==oo){ t[++tmp]=d[i]; c[t[tmp].pos]=tmp; } for (int i=1;i<=tmp;i++) d[i]=t[i]; eds=tmp; } void Solve(int l,int r,int cur,int eds,ll sum) { if (l==r) a[q[l].first]=q[l].second; for (int i=1;i<=eds;i++) e[cur][i].w=a[e[cur][i].pos],d[i]=e[cur][i],c[d[i].pos]=i; if (l==r){ ans[l]=sum; init(d,eds); sort(d+1,d+eds+1); for (int i=1;i<=eds;i++) if (Union(d[i].u,d[i].v)) ans[l]+=d[i].w; return; } for (int i=l;i<=r;i++) d[c[q[i].first]].w=-oo; sum+=contraction(eds); for (int i=l;i<=r;i++) d[c[q[i].first]].w=oo; reduce(eds); for (int i=1;i<=eds;i++) e[cur+1][i]=d[i]; int mid=(l+r)>>1; Solve(l,mid,cur+1,eds,sum); Solve(mid+1,r,cur+1,eds,sum); } int main() { freopen("t.in","r",stdin); freopen("t.out","w",stdout); read(n); read(m); read(Q); for (int i=1;i<=m;i++) read(e[0][i].u),read(e[0][i].v),read(e[0][i].w),a[i]=e[0][i].w,e[0][i].pos=i; for (int i=1;i<=Q;i++) read(q[i].first),read(q[i].second); Solve(1,Q,0,m,0); for (int i=1;i<=Q;i++) printf("%lld\n",ans[i]); return 0; }
相關推薦
[動態最小生成樹 CDQ分治 Kruscal] BZOJ 2001 [Hnoi2010]City 城市建設
兩個關鍵的操作: Reduction(刪除無用邊): 把待修改的邊標為INF,做一遍MST,把做完後不在MST中的非INF邊刪去(因為這些邊在原圖的情況下肯定更不可能選進MST的邊集,即無用邊); Contraction(縮必須邊,縮點): 把待修改的邊標為-INF,做
BZOJ 2001 [Hnoi2010]City 城市建設 LCT+分治(未成功卡時卡過)
題意: 無向圖,求每次修改一條邊權值後的最小生成樹的邊權和。 解析: 網上題解都是些什麼CDQ重構圖的鬼畜演算法。 wyf大爺提出了用LCT以及分治解決這道題的辦法。 整個時間看做一個軸的話。 那麼每條邊的顏色必然是幾段連續的區間。 所以我們可
bzoj 2001 [Hnoi2010]City 城市建設
PS國是一個擁有諸多城市的大國,國王Louis為城市的交通建設可謂絞盡腦汁。Louis可以在某些城市之間修建道路,在不同的城市之間修建道路需要不同的花費。Louis希望建造最少的道路使得國內所有的城市連通。但是由於某些因素,城市之間修建道路需要的花費會隨著時間而改變,Louis會不斷得到某道路的修建代價改變
【最小生成樹】【kruscal】【貪心】CDOJ1636 夢後樓臺高鎖,酒醒簾幕低垂
ext 停止 min 時間 定義 cal ssi sin 我們 給你一個有n個點和m條邊的無向連通圖,每條邊都有一個權值ww.我們定義,對於一條路徑,它的Charm value為該路徑上所有邊的權值的最大值與最小值的差.詢問從1到n的所有路徑的Charm value的最小值
bzoj2001 [Hnoi2010]City 城市建設 動態最小生成樹
昨晚水冬令營課件看到這題,感覺蠻有意思的,學習了一波,抽象式理解,今天又看了大佬的程式碼,徹底弄懂了這個東西。 WC2013顧昱洲在《淺談一類分治演算法》中提到了動態最小生成樹的分治做法,我來梳理下我的理解。 這個演算法有兩個重要的操作: ①reduction: 對於一張圖
BZOJ2001 [Hnoi2010]City 城市建設 CDQ分治
bool 想法 isp tle .html getc find 存在 val 2001: [Hnoi2010]City 城市建設 Time Limit: 20 Sec Memory Limit: 162 MB Description PS國是一個擁有諸多城市
BZOJ2001 [Hnoi2010]City 城市建設 【CDQ分治 + kruskal】
city 刪掉 fin www 題目 ref air pan PE 題目鏈接 BZOJ2001 題解 CDQ分治神題。。。 難想難寫。。 比較樸素的思想是對於每個詢問都求一遍\(BST\),這樣做顯然會爆 考慮一下時間都浪費在了什麽地方 我們每次求\(BST\)實際上就只有
[BZOJ2001][Hnoi2010]City 城市建設(CDQ分治+並查集)
CDQ分治。 和AHOI2013連通圖差不多,但彷彿還要噁心…… 基本思想是CDQ分治往下遞迴時,不斷地縮小圖的規模。 下面考慮怎樣處理[l,r][l,r]範圍內的操作。 (1)先找出在[l,r][l,r]時,必須加入的邊。 具體地,先假設操作[l,r
BZOJ-4777 Switch Grass(最小生成樹+動態開點線段樹+可刪堆)
題意 給定一張 n n n 和節點,
BZOJ 1016: [JSOI2008]最小生成樹計數
gis style bool tchar line 二次 ons find continue 二次聯通門 : BZOJ 1016: [JSOI2008]最小生成樹計數 /* BZOJ 1016: [JSOI2008]最小生成樹計數 對原圖
BZOJ 1626 [Usaco2007 Dec]Building Roads 修建道路:kruskal(最小生成樹)
push_back spa pri family sca iostream 長度 con end 題目鏈接:http://www.lydsy.com/JudgeOnline/problem.php?id=1626 題意: 有n個農場,坐標為(x[i],y[i])。
BZOJ 2561 最小生成樹
void sca open ems ostream cap sizeof 雙向 sap 第一眼瞎那啥貪心,然後覺得不太對勁,就滾去看題解,發現是網絡流OTZ 模擬Kruskal的過程發現,若<u,v>要在最小生成樹中出現,權值則小於<u,v>的邊不能
BZOJ 1601 [Usaco2008 Oct]灌水:最小生成樹
ostream opera 兩種方法 數字 {} back 一個 stream print 題目鏈接:http://www.lydsy.com/JudgeOnline/problem.php?id=1601 題意: Farmer John已經決定把水灌到他的n(1<
BZOJ 1232 [Usaco2008Nov]安慰奶牛cheer:最小生成樹【樹上dfs性質】
space bsp void pre print 一次 targe algorithm names 題目鏈接:http://www.lydsy.com/JudgeOnline/problem.php?id=1232 題意: 給你一個無向圖,n個點,m條邊。 每條邊有
BZOJ 1016--最小生成樹計數(深搜&kruskal)
names 連通性 如果 int 沒有 計數 ++ struct include 想我這樣的zz根本不會矩陣樹。。。。。 題目鏈接: http://www.lydsy.com/JudgeOnline/problem.php?id=1016 S
bzoj 1016 [JSOI2008]最小生成樹計數
nbsp 後乘 getch 題解 align math rip main bool [JSOI2008]最小生成樹計數 Description 現在給出了一個簡單無向加權圖。你不滿足於求出這個圖的最小生成樹,而希望知道這個圖中有多少個不同的最小生成樹。(如果兩顆
[bzoj] 3295 動態逆序對 || CDQ分治
blog 順序 lld online 添加 namespace har -i pre 原題 給1到n的一個排列,按照某種順序依次刪除m個元素,求每刪除一個元素之前統計整個序列的逆序對數。 CDQ板題。因為刪除不好處理,所以將其反過來,變為每次添加。每個數都賦予一個添加時間
BZOJ 2561 最小生成樹 | 網絡流 最小割
== str queue min ace math ans dfs markdown 鏈接 BZOJ 2561 題解 用Kruskal算法的思路來考慮,邊(u, v, L)可能出現在最小生成樹上,就是說對於所有邊權小於L的邊,u和v不能連通,即求最小割; 對於最大生成樹的情
bzoj 2561: 最小生成樹
online std urn 直接 stat bre 一行 add accept 2561: 最小生成樹 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2248 Solved: 1073[Submit][Status][
bzoj 2561: 最小生成樹【最小割】
inf front ostream ring pos clu clas 要求 || 看錯題了以為多組詢問嚇得不行…… 其實還挺好想的,就是數據範圍一點都不網絡流。把U作為s,V作為t,以最小生成樹為例,(U,V,L)要在最小生成樹上,就要求所有邊權比L小的邊不能連通(U,V