1. 程式人生 > >[動態最小生成樹 CDQ分治 Kruscal] BZOJ 2001 [Hnoi2010]City 城市建設

[動態最小生成樹 CDQ分治 Kruscal] BZOJ 2001 [Hnoi2010]City 城市建設

兩個關鍵的操作: Reduction(刪除無用邊): 把待修改的邊標為INF,做一遍MST,把做完後不在MST中的非INF邊刪去(因為這些邊在原圖的情況下肯定更不可能選進MST的邊集,即無用邊); Contraction(縮必須邊,縮點): 把待修改的邊標為-INF,做一遍MST,在MST中的非-INF邊為必須邊(因為這些邊在原圖的情況下也一定會被選進MST),縮點。
#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 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