ABC 364 F - Range Connect MST 题解

一副扑克牌,去掉 1 到 K,剩下就是我,赛后十秒过,我是 joker。🤡

\(n\)\(q\) 同阶。

最原始的做法,把 \(q\) 次连边按大小从小到大排序,对于第 \(i\) 次连边把 \(n+i\) 和满足 \(l_i\le j \le r_i\) 的节点 \(j\) 依次尝试连边,如果两个点不在同一个连通块,那么连边。

这样肯定过不了。注意到,对于 \(1\)\(n\) 中的节点,一个连通块中点的编号是连续的,那么可以用线段树优化。线段树中的一个区间维护这样的信息:如果该区间的点都在同一连通块里,那么值就是连通块的编号;反之,就是 \(0\)。这是容易维护的。

考虑连边。把 \([l_i,r_i]\) 拆分成若干个线段树上的区间,每一个小区间递归着去连边。如果递归到的区间的点都在同一连通块里,那么就尝试把这个连通块里的随便哪一个点向 \(n+i\) 连边,因为只需要连一次,整个连通块都会和 \(n+i\) 联通;如果不在同一连通块里,那么继续递归。

由于连边的次数不会太多,是 \(O(n)\) 级别的,那么时间复杂度是 \(O(n\log n)\)

点击开 D
const int N=200099;
int n,q,tr[N<<2]={},fa[N<<1]={};
ll ans=0;
int father(int x) { return fa[x]=fa[x]==x?x:father(fa[x]); }
void link(int x,int y) { return fa[father(y)]=father(x),void(); }
bool same(int x,int y) { return father(x)==father(y); }
struct edge {
	int l,r; ll c;
	friend bool operator < (const edge a,const edge b) {
		return a.c<b.c;
	}
} e[N]={};
#define lson (x<<1)
#define rson (x<<1|1)
void update(int x) {
	tr[lson]=father(tr[lson]),tr[rson]=father(tr[rson]);
	if(!tr[lson]||!tr[rson]) tr[x]=0;
	else if(same(tr[lson],tr[rson])) tr[x]=father(tr[lson]);
	else tr[x]=0;
	return ;
}
void setup(int x,int l,int r) {
	if(l==r) return tr[x]=l,void();
	int mid=l+r>>1;
	setup(lson,l,mid),setup(rson,mid+1,r);
	return update(x);
}
void link(int x,int l,int r,int p,ll cost) {
	if(tr[x]) {
		if(!same(tr[x],p))
			link(tr[x],p),ans+=cost;
		if(l==r) tr[x]=father(l); else update(x);
		return ;
	}
	if(l==r) return ;
	int mid=l+r>>1;
	link(lson,l,mid,p,cost);
	link(rson,mid+1,r,p,cost);
	update(x);
	return ;
}
void change(int x,int l,int r,int L,int R,int p,ll cost) {
	if(L<=l&&r<=R) return link(x,l,r,p,cost);
	int mid=l+r>>1;
	if(L<=mid) change(lson,l,mid,L,R,p,cost);
	if(mid<R) change(rson,mid+1,r,L,R,p,cost);
	update(x);
	return ;
}
int main()
{
//	usefile("mst");
	int i;
	read(n,q);
	for(i=1;i<=q;++i)
		read(e[i].l,e[i].r,e[i].c);
	for(i=1;i<=n+q;++i)
		fa[i]=i;
	sort(e+1,e+1+q);
	setup(1,1,n);
	for(i=1;i<=q;++i)
		change(1,1,n,e[i].l,e[i].r,n+i,e[i].c);
	for(i=1;i<=n+q;++i)
		if(!same(i,1)) {
			printf("-1\n");
			return 0;
		}
	printf("%lld\n",ans);
	return 0;
}
posted @ 2024-07-27 22:07  fydj  阅读(126)  评论(0编辑  收藏  举报