樹(tree) - 題解(帶權並查集)

Jerrycyx發表於2024-08-02

樹(tree)

時間限制:C/C++ 2000MS,其他語言 4000MS
記憶體限制:C/C++ 256MB,其他語言 512MB

描述

給定一個 \(n\) 個結點,\(n−1\) 條邊的有根樹。
\(i\) 條邊可以用 (\(a_i,b_i\)) 來描述,它表示連線結點 \(a_i\) 和結點 \(b_i\) 的一條邊,其中結點 \(a_i\) 是結點 \(b_i\) 的父節點。
一共有 \(n−1\) 次查詢:第 \(i\) 次查詢包含一個整數 \(c_i\),詢問由前 \(i\) 條邊構成的圖(森林)中從結點 \(c_i\) 開始的最長簡單路徑的長度。
資料保證不存在 \(j\) 使得 \(1≤j≤i\)\(b_j=c_i\),即 \(c_i\) 是前 \(i\) 條邊構成的森林中一棵樹的根。

輸入描述

輸入有多組測試用例,第一行包含一個整數 \(t(1≤t≤10^5)\) ,表示接下來有 \(t\) 組測試用例。
每組測試用例第一行包含一個整數 \(n(2≤n≤10^6)\),表示樹的結點數。
接下來 \(n−1\) 行每行包含三個整數 \(a_i,b_i,c_i\) \((1≤a_i,b_i,c_i≤n,a_i≠b_i)\),表示結點 \(b_i\) 的父結點是結點 \(a_i\) ,第 \(i\) 次詢問是 \(c_i\)
資料保證:
對每一個測試用例,\(n−1\) 條邊形成一個有根樹。
對每一個測試用例,對任意 \(1≤i≤n−1\),保證不存在 \(j\) 使得 \(1≤j≤i\)\(b_j=c_i\)
所有測試用例中,\(n\) 的總和不超過 \(10^6\)

輸出描述

對每一個測試用例,一行輸出 \(n−1\) 個整數,第 \(i\) 個整數表示第 \(i\) 次詢問的答案。

用例輸入 1

6
4
3 4 1
2 3 1
1 2 1
4
3 4 3
2 1 2
3 2 3
4
1 2 1
3 4 3
2 3 1
4
2 3 1
2 4 2
1 2 1
2
1 2 1
2
2 1 2

用例輸出 1

0 0 3
1 1 2
1 1 3
0 1 2
1
1

用例輸入 2

2
5
1 2 3
1 3 4
3 4 1
1 5 1
15
10 14 10
5 8 5
1 3 1
4 7 10
2 5 2
1 2 1
3 4 1
9 10 9
11 13 11
5 6 1
10 12 9
8 9 1
11 15 11
7 11 1

用例輸出 2

0 0 2 2
1 1 1 1 2 3 3 2 1 3 2 6 1 6

提示

\(1≤t≤10^5\)
\(2≤n≤10^6\)

解析

由題意得 \(c_i\) 為某樹的根;
由於不可能將兩個非根結點連線在一起,所以 \(b_i\) 一定是樹根。

用帶權並查集處理深度和子樹的最大深度即可。

程式碼

#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;

inline int read()
{
	int x=0,w=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^'0');ch=getchar();}
	return x*w;
}

const int N=2e6+5,M=5e6+5;
int T,n;

int fa[N],dist[N],maxdep[N];
inline void uInit()
{
	for(int i=1;i<=n;i++)
	{
		fa[i]=i;
		maxdep[i]=dist[i]=0;
	}
	return;
}
int uask(const int x)
{
	if(fa[x]==x) return x;
	else
	{
		const int oldfa=fa[x];
		fa[x]=uask(fa[x]);
		dist[x]=dist[x]+dist[oldfa];
		maxdep[fa[x]]=max(maxdep[fa[x]],dist[x]); //ÕâÒ»ÐпÉÒÔÊ¡ÂÔ 
		return fa[x];
	}
}
inline void umerge(const int x,const int y)
{
	const int rtx=uask(x),rty=uask(y);
	if(rtx==rty) return;
	fa[rty]=rtx;
	dist[rty]=dist[x]+1-dist[y]; //dist[y]+dist[rty]=dist[x]+dis(x,y)
	maxdep[rtx]=max(maxdep[rtx],maxdep[rty]+dist[rty]);
	return;
}

int main()
{
	T=read();
	while(T--)
	{
		n=read();
		uInit();
		for(int i=1;i<n;i++)
		{
			int a=read(),b=read(),q=read();
			umerge(a,b);
			printf("%d ",maxdep[q]);
		}
		putchar('\n');
	}
	return 0;
}

相關文章