P3206 [HNOI2010]城市建設

P3206 [HNOI2010]城市建設

題目描述

無向圖上修改邊權,動態維護MSTMST,求每次修改後的MST的權值和。

Solution

有一個簡單好想的做法——LCTLCT+線段樹分治。
考慮每次加邊,若形成了一個環,則把環上最大的一條邊刪掉,LCTLCT維護。
然後刪邊就套一個線段樹分治,刪邊操作就變成了加邊和回退操作,直接做就行了。
時間複雜度:大常數O(nlg2n)O(nlg^2n),似乎卡不過。

還有一個神奇的做法。
因爲一次修改操作只會改動MST上的一條邊,所以我們考慮通過線段樹分治,分治區間爲[l,r][l,r],將點數和邊數都保持在O(rl)O(r-l)級別。

[l,r][l,r]中的操作涉及的邊集爲SS,當前點集爲VV,當前邊集(不包含SS中的邊)爲EE
有兩個顯然的引理:
1.把SS的邊權值都設爲INFINF,將其設爲SS',在(V,E+S)(V,E+S')MSTMST,顯然若此時不在MSTMST中的邊在之後的分治過程中都不可能在MSTMST中了,直接在EE刪去即可。
2.把SS的邊權值都設爲INF-INF,將其設爲SS'',在(V,E+S)(V,E+S'')MSTMST,顯然若此時在MSTMST中的邊在之後的分治過程中都一定在MSTMST中了,直接在EE刪去,並加上貢獻。

通過這兩個引理就可以讓E,V=O(rl)|E|,|V|=O(r-l)
時間複雜度T(n)=T(n/2)+O(nlgn)=O(nlg2n)T(n)=T(n/2)+O(nlgn)=O(nlg^2n),常數比較小。

#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <ctime>
#include <cassert>
#include <string.h>
//#include <unordered_set>
//#include <unordered_map>
//#include <bits/stdc++.h>

#define MP(A,B) make_pair(A,B)
#define PB(A) push_back(A)
#define SIZE(A) ((int)A.size())
#define LEN(A) ((int)A.length())
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define fi first
#define se second

using namespace std;

template<typename T>inline bool upmin(T &x,T y) { return y<x?x=y,1:0; }
template<typename T>inline bool upmax(T &x,T y) { return x<y?x=y,1:0; }

typedef long long ll;
typedef unsigned long long ull;
typedef long double lod;
typedef pair<int,int> PR;
typedef vector<int> VI;

const lod eps=1e-11;
const lod pi=acos(-1);
const int oo=1<<30;
const ll loo=1ll<<62;
const int mods=998244353;
const int MAXN=50005;
const int INF=0x3f3f3f3f;//1061109567
/*--------------------------------------------------------------------*/
inline int read()
{
	int f=1,x=0; char c=getchar();
	while (c<'0'||c>'9') { if (c=='-') f=-1; c=getchar(); }
	while (c>='0'&&c<='9') { x=(x<<3)+(x<<1)+(c^48); c=getchar(); }
	return x*f;
}
PR a[MAXN];
int flag[MAXN],Flag[MAXN],fa[MAXN],vn[18],en[18],V[18][MAXN],To[MAXN],b[MAXN];
struct enode{ int u,v,c,id; } e[MAXN],E[18][MAXN],tmp[MAXN];
inline int compareE(enode x,enode y) { return x.c<y.c; }
inline int find(int x) { return fa[x]==x?fa[x]:fa[x]=find(fa[x]); }
inline void work1(int n,int m,int l,int r,int dep)
{
	for (int i=l;i<=r;i++) flag[a[i].fi]=1;
	for (int i=1;i<=m;i++)
	{
		tmp[i]=E[dep][i];
		if (flag[E[dep][i].id]) tmp[i].c=INF;
	}
	sort(tmp+1,tmp+m+1,compareE);
	for (int i=1;i<=n;i++) fa[i]=i;
	for (int i=1;i<=m;i++)
	{
		int x=find(tmp[i].u),y=find(tmp[i].v),c=tmp[i].c;
		if (x!=y) fa[x]=y;
		else if (c!=INF) Flag[tmp[i].id]=-1;
	}
	for (int i=l;i<=r;i++) flag[a[i].fi]=0;
}
inline void work2(int n,int m,int l,int r,int dep)
{
	for (int i=l;i<=r;i++) flag[a[i].fi]=1;
	for (int i=1;i<=m;i++)
	{
		tmp[i]=E[dep][i];
		if (flag[E[dep][i].id]) tmp[i].c=-INF;
	}
	sort(tmp+1,tmp+m+1,compareE);
	for (int i=1;i<=n;i++) fa[i]=i;
	for (int i=1;i<=m;i++)
	{
		int x=find(tmp[i].u),y=find(tmp[i].v),c=tmp[i].c;
		if (x!=y) 
		{
			fa[x]=y;
			if (c!=-INF) Flag[tmp[i].id]=1;
		}
	}
	for (int i=l;i<=r;i++) flag[a[i].fi]=0;
}
inline void solve(int l,int r,int dep,ll Ans)
{
	int n=vn[dep],m=en[dep];
	if (l==r)
	{
		for (int i=1;i<=m;i++)
		{
			tmp[i]=E[dep][i];
			if (tmp[i].id==a[l].fi) tmp[i].c=a[l].se;
		}
		sort(tmp+1,tmp+m+1,compareE);
		for (int i=1;i<=n;i++) fa[i]=i;
		for (int i=1;i<=m;i++)
		{
			int x=find(tmp[i].u),y=find(tmp[i].v),c=tmp[i].c;
			if (x!=y) fa[x]=y,Ans+=c;
		}
		printf("%lld\n",Ans);
		return;
	}
	for (int i=1;i<=m;i++) Flag[E[dep][i].id]=0;
	work1(n,m,l,r,dep);
	work2(n,m,l,r,dep);
	vn[dep+1]=en[dep+1]=0;
	for (int i=1;i<=n;i++) fa[i]=i;
	for (int i=1;i<=m;i++)
		if (Flag[E[dep][i].id]==1) 
		{
			int x=find(E[dep][i].u),y=find(E[dep][i].v);
			if (x!=y) fa[x]=y;
		}
		
	for (int i=1;i<=n;i++) 
		if (fa[i]==i) V[dep+1][++vn[dep+1]]=V[dep][i],To[i]=vn[dep+1];
	for (int i=1;i<=m;i++)
		if (Flag[E[dep][i].id]==1) Ans+=E[dep][i].c;
		else if (Flag[E[dep][i].id]==0) 
		{
			int x=find(E[dep][i].u),y=find(E[dep][i].v);
			if (x!=y) E[dep+1][++en[dep+1]]=(enode){To[x],To[y],E[dep][i].c,E[dep][i].id};
		}
		
	int mid=(l+r)>>1;
	solve(l,mid,dep+1,Ans);
	for (int i=l;i<=mid;i++) b[a[i].fi]=a[i].se;
	for (int i=1;i<=en[dep+1];i++)
		if (b[E[dep+1][i].id]!=INF) E[dep+1][i].c=b[E[dep+1][i].id];
	for (int i=l;i<=mid;i++) b[a[i].fi]=INF;
	solve(mid+1,r,dep+1,Ans);
}
int main()
{
	int n=read(),m=read(),q=read();
	for (int i=1;i<=m;i++) 
	{
		int u=read(),v=read(),c=read();
		e[i]=(enode){u,v,c,i};
	}
	for (int i=1;i<=q;i++)
	{
		int x=read(),y=read();
		a[i]=MP(x,y);
	}
	vn[0]=n,en[0]=m;
	for (int i=1;i<=n;i++) V[0][i]=i;
	for (int i=1;i<=m;i++) E[0][i]=e[i],b[i]=INF;
	solve(1,q,0,0);
	return 0;
}

代碼有點醜……

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章