TAG
- 带权并查集 带权并查集 带权并查集时间复杂度
- O ( l o g ∗ n ) − 基于 r a n k 和路径压缩 O(log^*n) - 基于 rank 和 路径压缩 O(log∗n)−基于rank和路径压缩
//
#include<bits/stdc++.h>
using namespace std;
#define int long long // 开 long long
const int N=2e5+6;
int dad[N+5];
int dis[N+5];
vector<int> v;
inline void init()
{
for( int i=1;i<=N;i++ ) dad[i]=i;
}
inline int get_dad( int x )
{
if( dad[x]!=x )
{
int xdad=dad[x]; // 由于路径压缩导致 dad[x] 值被维护,所以需要暂存 dad[x] 以确保正确维护 dis[x]
dad[x]=get_dad(xdad);
dis[x]+=dis[xdad];
}
return dad[x];
}
void solve()
{
init(); //
int n,m;
scanf("%lld%lld",&n,&m );
for( int i=1;i<=m;i++ )
{
int x,y,data;
scanf("%lld%lld%lld",&x,&y,&data );
int tx=get_dad(x);
int ty=get_dad(y);
/*
1. `tx != ty`:不在同一棵树上时,直接合并是可行的
{
dad[tx] = ty;
{
树 tx 合并到 树 ty 上
}
dis[tx] = data + dis[y] - dis[x];
{
1. `dad[tx] = ty;`:tx -> ty
2. `dis[x] - dis[y] == data`:x -> y
3. x -> tx
4. y -> ty
tx -> ty = tx -> x -> y -> ty
dis[tx] = -dis[x] + data + dis[y] ;
}
}
2. `dis[x] - dis[y] == data`:在同一个棵树时,考虑其合法性
{
dad[tx] = ty;
{
树 tx 和树 ty 为同一棵树,等同于 dad[i] = i
}
dis[tx] = data + dis[y] - dis[x];
{
1. tx = ty = root, dis[tx] = 0
2. `dis[x] - dis[y] = data`:dis[y] - dis[x] = -data
3. data + dis[y] - dis[x] = 0
}
}
*/
if( tx!=ty || dis[x]-dis[y]==data )
{
v.push_back(i);
dad[tx]=ty;
dis[tx]=data+dis[y]-dis[x];
}
}
for( int i=0;i<v.size();i++ )
{
if( i ) putchar(' ');
printf("%lld",v[i] );
}
}
signed main()
{
int t=1;
// scanf("%d",&t );
while( t-- ) solve();
return 0;
}
实现细节
开 long long
暂存 dad[x]
init();
参考示意图
参考链接
作者 | 乐意奥AI