2001 Hnoi2010 City 城市建設

2021-07-24 12:35:26 字數 4229 閱讀 6056

time limit: 20 sec  

memory limit: 162 mb

submit: 1098  

solved: 539 [

submit][

status][

discuss]

ps國是乙個擁有諸多城市的大國,國王louis為城市的交通建設可謂絞盡腦汁。louis可以在某些城市之間修建道路,在不同的城市之間修建道路需要不同的花費。louis希望建造最少的道路使得國內所有的城市連通。但是由於某些因素,城市之間修建道路需要的花費會隨著時間而改變,louis會不斷得到某道路的修建代價改變的訊息,他希望每得到一條訊息後能立即知道使城市連通的最小花費總和, louis決定求助於你來完成這個任務。

檔案第一行包含三個整數n,m,q,分別表示城市的數目,可以修建的道路個數,及收到的訊息個數。 接下來m行,第i+1行有三個用空格隔開的整數xi,yi,zi(1≤xi,yi≤n, 0≤zi≤50000000),表示在城市xi與城市yi之間修建道路的代價為zi。接下來q行,每行包含兩個數k,d,表示輸入的第k個道路的修建代價修改為d(即將zk修改為d)。

輸出包含q行,第i行輸出得知前i條訊息後使城市連通的最小花費總和。

5 5 3

1 2 1

2 3 2

3 4 3

4 5 4

5 1 5

1 61 1

5 314109

【資料規模】 對於20%的資料, n≤1000,m≤6000,q≤6000。 有20%的資料,n≤1000,m≤50000,q≤8000,修改後的代價不會比之前的代價低。 對於100%的資料, n≤20000,m≤50000,q≤50000。 [

submit][

status][

discuss]

cdq分治,,啊。。想也想不到

傳送門這裡的ppt有很詳細的介紹了

所以就補充一點筆記吧。。

每次修改只是改了一條邊的權值,因此,修改之後的mst有著極大的相似性,藉此分治

定義過程solve(l,r)為處理(l,r)的詢問,然後將圖修改為做完(l,r)修改之後的狀態

為了很好地實現修改和詢問操作,要明確一些事情,,

一開始得到圖g,乙個點集v和乙個邊集e,要做mst

假如強制e的某個子集s中所有邊不選,然後做一次mst,假設得到一棵樹t

那麼e - t中不屬於s的所有邊,無論s中的所有邊邊權如何改變,永遠都不會被選

因為我們已經能找到更優的東西,且s的改變無法影響e - t中不屬於s的邊

再強制s中所有邊優先考慮,做一次mst,得到一棵樹t'

此時t' - s的邊無論s中所有邊邊權如何改變,永遠都會存在於mst中

因為這些邊是優先s的情況下選擇的,s無論如何改變,只能更劣,並不影響這些邊的選擇

現在,定義s = ,

那麼每次,我們執行操作1,刪掉那些永遠不會被選的邊,記這個操作為reduction

然後對於剩下的邊,執行操作2,強制加入所有必選邊,或是說縮點,記這個操作為contraction

那麼每次,reduction後,剩下的邊的數量最壞是|s| + n - 1,就是g - s中的邊能生成一棵樹

而contraction後,剩下的點的數量最壞是|s|,也就是|s|中的邊剛好無環

整個過程放在分治裡,每次|s|會縮小一半,因而操作1剩下的邊數最壞約是3*s,因為n和上一層分治乙個數量級

3已經可以看做是常數了,那麼我們只要在分治的時候reduction,contraction,將新圖傳遞給子孫解決

當l == r,剩下2~3個點,一些邊,此處先修改,然後做乙個mst,詢問就解決了,

返回的時候定義操作recover,能抵消reduction-contraction的操作就行了,

顯然recover的複雜度和reduction-contraction乙個數量級

縮點苟蒻是用安軼合併的並查集,然後solve(l,mid)返回時對邊集重新排序下

因此總的複雜度是o(nlog^n)

#include#include#include#include#include#include#include#includeusing namespace std;

const int maxn = 2e4 + 20;

const int maxm = 5e4 + 50;

typedef long long ll;

struct e

e(int x,int y,int w): x(x),y(y),w(w){}

}edgs[maxm];

struct data

data(int x,int y,int l): x(x),y(y),l(l){}

}s[maxm];

int n,m,q,cnt,tp,l[maxn],mark[maxm],po[maxm],d[maxm],fa[maxn],f[maxn];

ll ans[maxm];

bool cmp(const int &x,const int &y)

int getf(int x)

int getfa(int x)

void merge(int x,int y)

void reset_fa(vector v)

}void reduction(vector &v,vector &g)

}void contraction(vector &g,vector &t,ll &tot)

for (int i = 0; i < g.size(); i++)

e e = edgs[g[i]];

int x = getf(e.x),y = getf(e.y);

int fx = getfa(x),fy = getfa(y);

if (fx == fy)

tot += 1ll*e.w;

merge(x,y); fa[fx] = fy; }}

void recover(int cur)

}void solve(int l,int r,vector &v,ll tot)

ans[l] = tot;

recover(cur);

return;

} ++cnt; int mid = (l + r) >> 1;

for (int i = l; i <= r; i++) mark[po[i]] = cnt;

vector g,t; g.clear(); t.clear();

int cur = tp;

reduction(v,g);

contraction(g,t,tot);

solve(l,mid,t,tot);

sort(t.begin(),t.end(),cmp);

solve(mid+1,r,t,tot);

recover(cur);

}int main()

for (int i = 1; i <= n; i++) f[i] = i,l[i] = 1;

for (int i = 1; i <= q; i++) scanf("%d%d",&po[i],&d[i]);

vector v; v.clear();

for (int i = 1; i <= m; i++) v.push_back(i);

sort(v.begin(),v.end(),cmp);

solve(1,q,v,0);

for (int i = 1; i <= q; i++) printf("%lld\n",ans[i]);

return 0;

}

BZOJ2001 HNOI2010 城市建設

題目大意 動態最小生成樹,可以離線,每次修改後回答,點數20000,邊和修改都是50000。顧昱洲是真的神 顧昱洲 一類分治演算法 講的很妙,大致的幾個注意點在 裡面也有提到。include include include include include include define ll long...

HNOI2001 產品加工

題目描述 某加工廠有a b兩台機器,來加工的產品可以由其中任何一台機器完成,或者兩台機器共同完成。由於受到機器效能和產品特性的限制,不同的機器加工同一產品所需的時間會不同,若同時由兩台機器共同進行加工,所完成任務又會不同。某一天,加工廠接到n個產品加工的任務,每個任務的工作量不盡一樣。你的任務就是 ...

HNOI2001 產品加工

hnoi2001 產品加工 有機器甲乙二者,加工產品者也.今有 n 個產品,加工於甲需耗時間 t 加工於乙需耗時間 t 二者同時為其加工需耗時間 t 若 t 為 0 則表示無法用此方式加工 機器者,專一者也,一時只加工一產品也.試問加工完畢最小時間有幾何.挺神奇的一道題.一開始考慮開三個陣列 f 3...