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;
}