樹論

ProtectEMmm發表於2024-09-02

樹論

LCT

class C_LinkCutTree
{
public:
	int rev[N], fa[N], ch[N][2];
	/*====================*/
	bool Which(int x)
	{
		return ch[fa[x]][1] == x;
	}
	bool IsRoot(int x)
	{
		return ch[fa[x]][Which(x)] != x;
	}
	/*====================*/
	void PushUp(int x)
	{
		/*PushUp*/
	}
	void PushAll(int x)
	{
		if (!IsRoot(x))
		{
			PushAll(fa[x]);
		}
		PushDown(x);
	}
	void PushDown(int x)
	{
		if (rev[x])
		{
			swap(ch[x][0], ch[x][1]);
			rev[ch[x][0]] ^= 1;
			rev[ch[x][1]] ^= 1;
			rev[x] = 0;
		}
		/*PushDown*/
	}
	/*====================*/
	void Rotate(int x)
	{
		int y = fa[x], z = fa[y], w = Which(x);
		if (!IsRoot(y)) ch[z][Which(y)] = x; fa[x] = z;
		ch[y][w] = ch[x][w ^ 1];
		if (ch[y][w]) fa[ch[y][w]] = y;
		ch[x][w ^ 1] = y; fa[y] = x;
		PushUp(y); PushUp(x);
	}
	void Splay(int x)
	{
		PushAll(x);
		for (; !IsRoot(x); Rotate(x))
		{
			if (!IsRoot(fa[x]))
			{
				Rotate(Which(x) == Which(fa[x]) ? fa[x] : x);
			}
		}
	}
	/*====================*/
	void Access(int x)
	{
		for (int p = 0; x; p = x, x = fa[x])
		{
			Splay(x), ch[x][1] = p, PushUp(x);
		}
	}
	/*====================*/
	int FindRoot(int x)
	{
		Access(x); Splay(x);
		while (ch[x][0]) x = ch[x][0];
		Splay(x); return x;
	}
	void MakeRoot(int x)
	{
		Access(x); Splay(x); rev[x] ^= 1;
	}
	/*====================*/
	void Cut(int u, int v)
	{
		Split(u, v);
		if (fa[u] == v && !ch[u][1])
		{
			ch[v][0] = fa[u] = 0;
		}
	}
	void Link(int u, int v)
	{
		MakeRoot(u); fa[u] = v;
	}
	/*====================*/
	void Split(int u, int v)
	{
		MakeRoot(u); Access(v); Splay(v);
	}
	/*====================*/
	int LCA(int u, int v)
	{
		Access(u); int ans = 0;
		for (int child = 0; v; child = v, v = fa[v])
		{
			Splay(v); ch[v][1] = child; ans = v;
		}
		return ans;
	}
};

LCA

樹剖法

class C_LCA
{
private:
	struct Node
	{
		int pre, dep, siz, son, top;
		Node(void)
		{
			pre = -1, dep = +0, siz = +1, son = -1, top = -1;
		}
	};
	/*====================*/
	int root;
	vector<int>* G;
	vector<Node>node;
	/*====================*/
	void DFS1(int pre, int cur)
	{
		node[cur].pre = pre;
		node[cur].dep = node[pre].dep + 1;
		for (auto nxt : G[cur])
		{
			if (nxt != pre)
			{
				DFS1(cur, nxt);
				node[cur].siz += node[nxt].siz;
				if (node[cur].son == -1)
				{
					node[cur].son = nxt;
				}
				else if (node[nxt].siz > node[node[cur].son].siz)
				{
					node[cur].son = nxt;
				}
			}
		}
	}
	void DFS2(int cur, int top)
	{
		node[cur].top = top;
		if (node[cur].son != -1)
		{
			DFS2(node[cur].son, top);
			for (auto nxt : G[cur])
			{
				if (nxt == node[cur].pre)continue;
				if (nxt == node[cur].son)continue;
				DFS2(nxt, nxt);
			}
		}
	}
public:
	void Init(int n, vector<int>G[], int root = 1)
	{
		this->G = G;
		this->root = root;
		node.assign(n + 1, Node());
		DFS1(root, root); DFS2(root, root);
	}
	int operator()(int u, int v)
	{
		while (node[u].top != node[v].top)
		{
			int topu = node[u].top;
			int topv = node[v].top;
			if (node[topu].dep > node[topv].dep)
			{
				u = node[topu].pre;
			}
			else
			{
				v = node[topv].pre;
			}
		}
		return node[u].dep > node[v].dep ? v : u;
	}
};

ST表法

class C_LCA
{
private:
	vector<int>* G;
	vector<int>dfn;
	vector<vector<int>>table;
	/*====================*/
	void DFS(int pre, int cur)
	{
		table[0][dfn[cur] = ++dfn[0]] = pre;
		for (auto nxt : G[cur])if (nxt != pre)DFS(cur, nxt);
	}
	int Get(int x, int y)
	{
		return dfn[x] < dfn[y] ? x : y;
	}
public:
	void Init(int n, vector<int>G[], int root = 1)
	{
		this->G = G; dfn.assign(n + 1, 0);
		table.assign(__lg(n) + 1, vector<int>(n + 1, 0));
		/*====================*/
		DFS(0, root);
		for (int d = 1; (1 << d) <= n; ++d)
		{
			for (int i = 1; i + (1 << d) - 1 <= n; ++i)
			{
				table[d][i] = Get(table[d - 1][i], table[d - 1][i + (1 << (d - 1))]);
			}
		}
	}
	int operator()(int u, int v)
	{
		if (u == v)return u;
		if ((u = dfn[u]) > (v = dfn[v]))swap(u, v);
		int d = __lg(v - u++); return Get(table[d][u], table[d][v - (1 << d) + 1]);
	}
};

樹雜湊

class C_TreeHash
{
private:
	vector<int>* G;
	map<vector<int>, int>mp;
	/*====================*/
	int DFS(int pre, int cur)
	{
		vector<int>vec;
		for (auto nxt : G[cur])
		{
			if (nxt != pre)
			{
				vec.push_back(DFS(cur, nxt));
			}
		}
		sort(vec.begin(), vec.end());
		if (mp.find(vec) == mp.end())
		{
			mp[vec] = mp.size();
		}
		return mp[vec];
	}
public:
	int operator()(vector<int>G[], int root)
	{
		this->G = G;
		return DFS(root, root);
	}
};

樹分治

點分治

class C_TCD
{
private:
	vector<int>* G;
	/*====================*/
	vector<int>siz;
	vector<bool>rooted;
	/*====================*/
	int centroid, ans_part;
	/*====================*/
	void DFS(int pre, int cur, int all)
	{
		siz[cur] = 1; int max_part = 0;
		for (auto nxt : G[cur])
		{
			if (nxt == pre)continue;
			if (rooted[nxt])continue;
			DFS(cur, nxt, all);
			siz[cur] += siz[nxt];
			max_part = max(max_part, siz[nxt]);
		}
		max_part = max(max_part, all - siz[cur]);
		if (max_part < ans_part)
		{
			ans_part = max_part, centroid = cur;
		}
	}
	int Centroid(int cur, int all)
	{
		centroid = -1; ans_part = all;
		DFS(cur, cur, all); return centroid;
	} 
	/*====================*/
	void CalcSon(int pre, int cur)
	{
		/*
			新增cur到右樹tree中
		*/
		for (auto nxt : G[cur])
		{
			if (nxt == pre)continue;
			if (rooted[nxt])continue;
			CalcSon(cur, nxt);
		}
	}
	void CalcRoot(int root)
	{
		/*
			初始化左庫lib
		*/
		for (auto son : G[root])
		{
			if (!rooted[son])
			{
				/*
					初始化右樹tree
				*/
				CalcSon(son, son);
				/*
					遍歷右樹tree匹配左庫lib
				*/
				/*
					新增右樹tree到左庫lib
				*/
			}
		}
	}
	/*====================*/
	void DividTree(int root)
	{
		rooted[root] = true; CalcRoot(root);
		for (auto son : G[root])
		{
			if (!rooted[son])
			{
				DividTree(Centroid(son, siz[son]));
			}
		}
	}
public:
	void operator()(int n, vector<int>G[])
	{
		this->G = G;
		siz.assign(n + 1, 0);
		rooted.assign(n + 1, false);
		DividTree(Centroid(1, n));
	}
};

K級祖先

class C_KthAncestor
{
private:
	int n, root; vector<int>* G;
	/*====================*/
	struct Node
	{
		int pre, dep, siz, son;
		int top, dfn, idx;
		Node(void)
		{
			pre = -1; dep = +0;
			siz = +1; son = -1;
			dfn = +0, idx = +0;
			top = -1;
		}
	};
	/*====================*/
	vector<Node>node; int cnt;
	/*====================*/
	void DFS1(int pre, int cur)
	{
		node[cur].pre = pre;
		node[cur].dep = node[pre].dep + 1;
		for (auto nxt : G[cur])
		{
			if (nxt != pre)
			{
				DFS1(cur, nxt); node[cur].siz += node[nxt].siz;
				if (node[cur].son == -1)
				{
					node[cur].son = nxt;
				}
				else if (node[nxt].siz > node[node[cur].son].siz)
				{
					node[cur].son = nxt;
				}
			}
		}
	}
	void DFS2(int cur, int top)
	{
		node[cur].top = top;
		node[cur].dfn = ++cnt;
		node[cnt].idx = cur;
		if (node[cur].son != -1)
		{
			DFS2(node[cur].son, top);
			for (auto nxt : G[cur])
			{
				if (nxt == node[cur].pre)continue;
				if (nxt == node[cur].son)continue;
				DFS2(nxt, nxt);
			}
		}
	}
public:
	void Init(int n, vector<int>G[], int root = 1)
	{
		node.assign(n + 1, Node());
		this->n = n, this->root = root, this->G = G;
		cnt = 0; DFS1(root, root); DFS2(root, root);
	}
	int operator()(int x, int k)
	{
		int topx = node[x].top;
		while (k > 0)
		{
			topx = node[x].top;
			if (node[x].dep - node[topx].dep < k)
			{
				k -= node[x].dep - node[topx].dep + 1;
				x = node[topx].pre;
			}
			else
			{
				x = node[node[x].dfn - k].idx; k = 0;
			}
		}
		return x;
	}
};

樹鏈剖分

重鏈剖分

class C_HLD
{
public:
	int n, root; vector<int>* G;
	/*====================*/
	struct Node
	{
		int pre, dep, siz, son;
		int top, dfn, idx;
		Node(void)
		{
			pre = -1; dep = +0;
			siz = +1; son = -1;
			dfn = +0, idx = +0;
			top = -1;
		}
	};
private:
	vector<Node>node; int cnt;
	/*====================*/
	void DFS1(int pre, int cur)
	{
		node[cur].pre = pre;
		node[cur].dep = node[pre].dep + 1;
		for (auto nxt : G[cur])
		{
			if (nxt != pre)
			{
				DFS1(cur, nxt); node[cur].siz += node[nxt].siz;
				if (node[cur].son == -1)
				{
					node[cur].son = nxt;
				}
				else if (node[nxt].siz > node[node[cur].son].siz)
				{
					node[cur].son = nxt;
				}
			}
		}
	}
	void DFS2(int cur, int top)
	{
		node[cur].top = top;
		node[cur].dfn = ++cnt;
		node[cnt].idx = cur;
		if (node[cur].son != -1)
		{
			DFS2(node[cur].son, top);
			for (auto nxt : G[cur])
			{
				if (nxt == node[cur].pre)continue;
				if (nxt == node[cur].son)continue;
				DFS2(nxt, nxt);
			}
		}
	}
public:
	void Init(int n, vector<int>G[], int root = 1)
	{
		node.assign(n + 1, Node());
		this->n = n, this->root = root, this->G = G;
		cnt = 0; DFS1(root, root); DFS2(root, root);
	}
	Node& operator[](int idx) { return node[idx]; }
};

樹的重心

class C_TreeCentroid
{
private:
	vector<int>siz;
	vector<int>* G;
	int centroid, ans_part;
	/*====================*/
	void DFS(int pre, int cur, int all)
	{
		siz[cur] = 1; int max_part = 0;
		for (auto nxt : G[cur])
		{
			if (nxt != pre)
			{
				DFS(cur, nxt, all);
				siz[cur] += siz[nxt];
				max_part = max(max_part, siz[nxt]);
			}
		}
		max_part = max(max_part, all - siz[cur]);
		if (max_part < ans_part)
		{
			ans_part = max_part, centroid = cur;
		}
	}
public:
	int operator()(int n, vector<int>G[])
	{
		this->G = G; siz.assign(n + 1, 0);
		centroid = -1; ans_part = n;
		DFS(1, 1, n); return centroid;
	}
};

樹上路徑求交

假設當前要求路徑 \((a,b)\)\((c,d)\) 的交。
\(d_x\) 表示 \(x\) 的深度。
先求出 \(p[4]={lca(a,c),lca(a,d),lca(b,c),lca(b,d)}\)
\(p\) 陣列按深度排序,取出深度較大的兩個,記為 \(p0,p1\)
若存在交,則 \((p0,p1)\) 即所求。
現在只需要判斷路徑是否有交。
\(p0\neq p1\),則一定有交。
否則若 \(d_{p0}=\max(d_{lca(a,b)},d_{lca(c,d)})\),也有交。
否則路徑不相交。

樹上啟發式合併

對於以 u 為根的子樹

①. 先統計它輕子樹(輕兒子為根的子樹)的答案,統計完後刪除資訊

②. 再統計它重子樹(重兒子為根的子樹)的答案,統計完後保留資訊

③. 然後再將重子樹的資訊合併到 u上

④. 再去遍歷 u 的輕子樹,然後把輕子樹的資訊合併到 u 上

⑤. 判斷 u 的資訊是否需要傳遞給它的父節點(u 是否是它父節點的重兒子)

void DFS(int root, int cur)
{
	cnt[node[cur].val]++;
	if (cnt[node[cur].val] > maxcnt)
	{
		ans[root] = node[cur].val;
		maxcnt = cnt[node[cur].val];
	}
	else if (cnt[node[cur].val] == maxcnt)
	{
		ans[root] += node[cur].val;
	}
	for (auto nxt : G[cur])
	{
		if (nxt == node[cur].pre)continue;
		if (nxt == node[root].son)continue;
		DFS(root, nxt);
	}
}
void DSU(int cur, bool keep)
{
	for (auto nxt : G[cur])
	{
		if (nxt == node[cur].pre)continue;
		if (nxt == node[cur].son)continue;
		DSU(nxt, false);
	}
	if (node[cur].son != -1)DSU(node[cur].son, true);
	if (node[cur].son != -1)
	{
		ans[cur] = ans[node[cur].son];
	}
	DFS(cur, cur);
	if (keep == false)
	{
		maxcnt = 0;
		for (int i = node[cur].dfn; i < node[cur].dfn + node[cur].siz; ++i)
		{
			cnt[node[node[i].idx].val]--;
		}
	}
}

相關文章