(動態)邊分治學習筆記


終於在刷了半個寒假的計數題后學習了(動態)邊分治,寫個博客記錄一下。

然而做完兩道題之后可能又不想管它了

以后再有練習的時候再更新吧。

用途

\(O(n\log n)\)\(O(n\log^2 n)\) 等復雜度內解決樹上路徑問題。

加了“動態”二字之后可以支持修改操作。

其實用途應該和點分治差不多。

實現

思路

類似於點分治,我們選出一條中心邊,使兩邊的節點數盡可能平均,作為該層的中心。

之后我們遍歷左右子樹得到左右子樹的信息,用某種方法合並,得到跨越中心邊的答案。

最后遞歸左右子樹,得到不過中心邊的答案。

代碼

先給個定義:

#define go(x) for (int i=head[x];i;i=edge[i].nxt)
#define v edge[i].t
struct hh{int t,nxt,w;}edge[sz<<1],e[sz<<1]; // e:原圖;edge:重構后的圖
int h[sz],head[sz],ec,ecnt=1;
void M_E_(int f,int t,int w) // 本來想寫M_E,然而這是保留字……
{
	e[++ec]=(hh){t,h[f],w};
	h[f]=ec;
	e[++ec]=(hh){f,h[t],w};
	h[t]=ec;
}
void make_edge(int f,int t,int w)
{
	edge[++ecnt]=(hh){t,head[f],w};
	head[f]=ecnt;
	edge[++ecnt]=(hh){f,head[t],w};
	head[t]=ecnt;
}

首先,有些圖(如菊花圖)不適合邊分治。我們需要加一些點和邊,使在答案不變的前提下構造出一個更善良的圖。

int cnt;
void rebuild(int x,int fa)
{
	int tmp=0;
	for (int i=h[x];i;i=e[i].nxt)
	{
		int v=e[i].t,w=e[i].w;
		if (v==fa) continue;
		if (!tmp) make_edge(x,v,w),tmp=x;
		else
		{
			int t=++cnt;
			make_edge(tmp,t,0);
			make_edge(t,v,w);
			tmp=t;
		}
		rebuild(v,x);
	}
}

然后是找中心邊:

bool del[sz]; // 是否已經分治過
int ct,ctS,sum; // 中心邊,最小size,總大小
int size[sz]; // 子樹大小
void calcS(int x,int fa)
{
	size[x]=1;
	go(x) if (v!=fa&&!del[i>>1])
	{
		calcS(v,x);
		size[x]+=size[v];
	}
}
void findct(int x,int fa)
{
	go(x) if (v!=fa&&!del[i>>1])
	{
		findct(v,x);
		int S=max(size[v],sum-size[v]);
		if (chkmin(ctS,S)) ct=i;
	}
}

接着是遍歷左右子樹:

int dis[sz],s[sz];
void calcDis(int x,int fa,int d,int side)
{
    dis[x]=d;s[x]=side;
    go(x) if (!del[i>>1]&&v!=fa) calcDis(v,x,d+edge[i].w,side);
}

最后是分治:

int divide(int x)
{
	calcS(x,0);
	ct=-1;ctS=1e9;sum=size[x];
	findct(x,0);
	if (ct==-1) return ...;
	int l=edge[ct].t,r=edge[ct^1].t;
	del[ct>>1]=1;
	calcDis(l,0,0,0);calcDis(r,0,0,1);
    int ret=-1e9;
    //do something ......
	ret=max(ret,max(divide(l),divide(r)));
	return ret;
}

沒了。

拓展

這東西是可以支持修改操作的。

對於每個原樹中的點,記錄它在哪些中心邊的子樹內,左子樹還是右子樹,它對這條中心邊的貢獻是什么。

對於每一條中心邊,維護一些數據結構存儲左右子樹的信息。

修改一個點時就從下至上維護中心邊的信息即可。

例題:洛谷P2056 [ZJOI2007]捉迷藏

例題

我做題少不敢瞎BB\(Q\omega Q\)

以后更新吧……


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM