bzoj2001 [Hnoi2010]City 城市建設 動態最小生成樹
昨晚水冬令營課件看到這題,感覺蠻有意思的,學習了一波,抽象式理解,今天又看了大佬的程式碼,徹底弄懂了這個東西。
WC2013顧昱洲在《淺談一類分治演算法》中提到了動態最小生成樹的分治做法,我來梳理下我的理解。
這個演算法有兩個重要的操作:
①reduction:
對於一張圖,reduction操作的目的是刪除一定不會出現在最小生成樹中的邊,以此減小圖的規模
流程:
我們假設對於當前這張圖,有k條邊待修改,將這k條邊權值設為inf,做最小生成樹,易知此時不在最小生成樹中的邊是不會在任何修改後出現在最小生成樹中的,所以將這些邊刪去,得到新圖。
②contraction:
對於一張圖,contraction操作的目的是將一定會出現
流程:
假設對於當前這張圖,有k條邊待修改,將這k條邊權值設為-inf,做最小生成樹,易知此時仍在最小生成樹中的邊在任何修改後都會出現在最小生成樹中嗎,所以將這些邊縮起來,得到新圖。
好了,操作梳理完了,怎麼利用這些操作解決問題呢?直接暴力模擬每個狀態的圖肯定是不行的,即使將圖的規模縮小到了最少的k+1個點和2k條邊,這個複雜度也是不能接受的。
但是顯然可以發現,一條邊的待修改狀態存在於一個區間內,考慮同一張圖P,對於在區間[l,r]中的修改進行reduction和contraction操作得到新圖S,對在區間[x,y]中的修改進行reduction和contraction操作的到的新圖T,若[x,y]∈[l,r],
程式碼:
#include<bits/stdc++.h> #define ll long long #define inf 1ll<<50 #define N 100005 using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int n,m,q,a[N],sum[50]; int f[N],c[N];ll ans[N]; int find(int x){return x==f[x]?x:f[x]=find(f[x]);} struct node{int x,y;}p[N]; struct edge{int x,y,pos;ll c;}t[N],e[50][N],d[N]; bool operator < (edge a,edge b){return a.c<b.c;} void clear(int x) { for(int i=1;i<=x;i++) f[d[i].x]=d[i].x, f[d[i].y]=d[i].y; } void contraction(int &tot,ll &adt) { int tmp=0; sort(d+1,d+1+tot);clear(tot); for(int i=1;i<=tot;i++) { int fx=find(d[i].x),fy=find(d[i].y); if(fx==fy)continue; f[fx]=fy;t[++tmp]=d[i]; } for(int i=1;i<=tmp;i++) f[t[i].x]=t[i].x, f[t[i].y]=t[i].y; for(int i=1;i<=tmp;i++) { if(t[i].c==-inf)continue; int fx=find(t[i].x),fy=find(t[i].y); adt+=t[i].c,f[fx]=fy; }tmp=0; for(int i=1;i<=tot;i++) { int fx=find(d[i].x),fy=find(d[i].y); if(fx==fy)continue; t[++tmp]=d[i]; t[tmp].x=find(d[i].x); t[tmp].y=find(d[i].y); c[d[i].pos]=tmp; }tot=tmp; for(int i=1;i<=tot;i++)d[i]=t[i]; } void reduction(int &tot) { sort(d+1,d+1+tot); clear(tot);int tmp=0; for(int i=1;i<=tot;i++) { int fx=find(d[i].x),fy=find(d[i].y); if(fx==fy) { if(d[i].c==inf) t[++tmp]=d[i],c[d[i].pos]=tmp; continue; }f[fx]=fy; t[++tmp]=d[i],c[d[i].pos]=tmp; }tot=tmp; for(int i=1;i<=tot;i++)d[i]=t[i]; } void solve(int l,int r,int now,ll adt) { int tot=sum[now]; if(l==r)a[p[l].x]=p[l].y; for(int j=1;j<=tot;j++) e[now][j].c=a[e[now][j].pos],d[j]=e[now][j],c[e[now][j].pos]=j; if(l==r) { clear(tot); sort(d+1,d+1+tot); for(int j=1;j<=tot;j++) { int fx=find(d[j].x),fy=find(d[j].y); if(fx==fy)continue; f[fx]=fy;adt+=d[j].c; }ans[l]=adt; return ; }int mid=(l+r)>>1; for(int i=l;i<=r;i++)d[c[p[i].x]].c=-inf; contraction(tot,adt); for(int i=l;i<=r;i++)d[c[p[i].x]].c=inf; reduction(tot); sum[now+1]=tot; for(int i=1;i<=tot;i++)e[now+1][i]=d[i]; solve(l,mid,now+1,adt); solve(mid+1,r,now+1,adt); } int main() { n=read(),m=read(),q=read(); for(int i=1;i<=m;i++) { e[0][i].x=read(),e[0][i].y=read(); e[0][i].pos=i,a[i]=e[0][i].c=read(); }sum[0]=m; for(int i=1;i<=q;i++) p[i].x=read(),p[i].y=read(); solve(1,q,0,0); for(int i=1;i<=q;i++) printf("%lld\n",ans[i]); }
相關推薦
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 城市建設
維護 amp while sample max ace down mes lld Description PS國是一個擁有諸多城市的大國,國王Louis為城市的交通建設可謂絞盡腦汁。Louis可以在某些城市之間修建道路,在不同的城市之間修建道路需要不同的花費。Loui
BZOJ2001 [Hnoi2010]City 城市建設 【CDQ分治 + kruskal】
city 刪掉 fin www 題目 ref air pan PE 題目鏈接 BZOJ2001 題解 CDQ分治神題。。。 難想難寫。。 比較樸素的思想是對於每個詢問都求一遍\(BST\),這樣做顯然會爆 考慮一下時間都浪費在了什麽地方 我們每次求\(BST\)實際上就只有
BZOJ2001: [Hnoi2010]City 城市建設
BZOJ 題意 給你一張 n n n個點
[BZOJ2001][Hnoi2010]City 城市建設(CDQ分治+並查集)
CDQ分治。 和AHOI2013連通圖差不多,但彷彿還要噁心…… 基本思想是CDQ分治往下遞迴時,不斷地縮小圖的規模。 下面考慮怎樣處理[l,r][l,r]範圍內的操作。 (1)先找出在[l,r][l,r]時,必須加入的邊。 具體地,先假設操作[l,r
bzoj2001: [Hnoi2010]City 城市建設 wikioi2332
/************************************************************** Problem: 2001 User: xujiahe Language: C++ Result: Accepted Time:4084 m
[動態最小生成樹 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會不斷得到某道路的修建代價改變
2001: [Hnoi2010]City 城市建設
當分治到區間[l,r]時: 如果l==r,直接跑mst,結束。否則: S1存初始邊和[1,l)的邊,S2存[l,r]的邊。 先把S2中的邊權全都改成inf,跑mst,S1中用不到的邊即為無用邊,直接刪去。 再把S2中的邊權全都改成-inf,跑mst,S1中仍被用到的邊即為必
C++ Prim演算法構造可以使n個城市連線的最小生成樹
問題描述:給定一個地區的n個城市間的距離網,用Prim演算法建立最小生成樹,並計算得到的最小生成樹的代價。 基本要求: 1、城市間的距離網採用鄰接矩陣表示,若兩個城市之間不存在道路,則將相應邊的權值設為自己定義的無窮大值。(要求至少10個城市,15條邊) 2、最小生
暢通工程之最低成本建設問題(最小生成樹(Kruskal)+並查集)
題目連結 某地區經過對城鎮交通狀況的調查,得到現有城鎮間快速道路的統計資料,並提出“暢通工程”的目標:使整個地區任何兩個城鎮間都可以實現快速交通(但不一定有直接的快速道路相連,只要互相間接通過快速路可達即可)。現得到城鎮道路統計表,表中列出了有可能建設成快速路
藍橋杯 歷屆試題 城市建設 最小生成樹
把碼頭作為0點處理。 首先判斷不建碼頭是否可以生成最小生成樹 最小生成樹用kruskal演算法,若對於代價<0的邊,直接加入 若可以:Min(最小生成樹(不建碼頭),最小生成樹(建碼頭)); 若不可:最小生成樹(建碼頭) #include "stdio.h" #in
牛客網NowCoder 2018年全國多校算法寒假訓練營練習比賽(第四場)A.石油采集(dfs) B.道路建設(最小生成樹prim) C.求交集(暴力) F.Call to your teacher(迪傑斯特拉亂用) H.老子的全排列呢(dfs)
初始 -o 地圖 意義 技術 tle bject ios urn 菜哭了。。。 A.石油采集 時間限制:C/C++ 1秒,其他語言2秒 空間限制:C/C++ 32768K,其他語言65536K 64bit IO Format: %lld 鏈
HDU 3371(城市聯通 最小生成樹-Kruskal)
fat names none one ios div style += 技術 題意是求將所有點聯通所花費的最小金額,如不能完全聯通,輸出 -1 直接Kruskal,本題帶來的一點教訓是 rank 是algorithm頭文件裏的,直接做變量名會導致編譯錯誤。沒查到 rank
BZOJ-4777 Switch Grass(最小生成樹+動態開點線段樹+可刪堆)
題意 給定一張 n n n 和節點,
bzoj 2001 CITY 城市建設 cdq分治
題目傳送門 題解: 對整個修改的區間進行分治。對於當前修改區間來說,我們對整幅圖中將要修改的邊權都先改成-inf,跑一遍最小生成樹,然後對於一條樹邊並且他的權值不為-inf,那麼這條邊一定就是樹邊了。然後我們把這些點都縮成一個點。然後,我們繼續對當前修改區間來說,我們把要修改的邊的邊權都修改成inf,跑一
面狀地物綜合——一種描述區域性城市模式的擴充套件最小生成樹
文獻原標題:An Extended Minimum Spanning Tree Method For Characterizing Local Urban Patterns 一、最小生成樹(MST) 將地圖中所有建築物看作連通圖G的頂點N(Node)用建築物的質心來作為頂點的位置; 將建築
動態維護最小生成樹(IOI2003Maintain)
WOJ2235 Maintain 描述 農夫約翰的奶牛們希望能夠在農場的N(1<=N<=200)塊田地中自由的旅遊,儘管這些田地被樹林分開了。他們希望能夠通過維護一對對田地間的路徑使得任意兩塊田地間都有通路。奶牛們可以沿著任一方向的維護的路徑旅遊。