LOJ#6510. 「雅礼集训 2018 Day8」A 题解

题目链接

不难发现题目要求一个不定根的最小树形图。

那么直接套板子即可。

\(O((n+m)\log n)\)

code :

#include <bits/stdc++.h>
#define LL long long
using namespace std;
template <typename T> void read(T &x){
	static char ch; x = 0,ch = getchar();
	while (!isdigit(ch)) ch = getchar();
	while (isdigit(ch)) x = x * 10 + ch - '0',ch = getchar();
}
const int N = 505,M = 150005;
const LL INF = 1000000000ll * 505ll * 505ll;
int n,m,ex[M],ey[M]; LL ev[M],ans;
struct Union_Find_Set{
	int fa[N];
	inline void init(int n){ for (int i = 1; i <= n; ++i) fa[i] = i; }
	inline int Find(int x){ return x == fa[x] ? x : (fa[x] = Find(fa[x])); }
	inline bool connect(int x,int y){ return Find(x) == Find(y); }
	inline void Merge(int x,int y){ fa[Find(x)] = Find(y); }
}S1,S2;
int pre[N],in[N],T[N],a[M],dis[M],lc[M],rc[M]; LL tag[M]; 
inline void Tag(int o,LL v){ if (o) tag[o] += v,ev[a[o]] += v; }
inline void down(int o){ if (tag[o]) Tag(lc[o],tag[o]),Tag(rc[o],tag[o]),tag[o] = 0; }
inline int Merge(int x,int y){
	if (!x || !y) return x|y;
	down(x); down(y); if (ev[a[y]] < ev[a[x]]) swap(x,y); rc[x] = Merge(rc[x],y);
	if (dis[rc[x]] > dis[lc[x]]) swap(lc[x],rc[x]); dis[x] = dis[rc[x]] + 1;
	return x;
}
inline void pop(int &x){ down(x),x = Merge(lc[x],rc[x]); }
inline bool chk(int e){ return !S2.connect(ex[e],ey[e]); }
queue<int>q;
int main(){
	int i,x,y,e;
	read(n),read(m); 
	for (i = 1; i <= m; ++i) read(ex[i]),read(ey[i]),read(ev[i]);
	for (i = 1; i <= n; ++i){ ++m; ex[m] = n+1,ey[m] = i,ev[m] = INF; q.push(i); } ++n;
	S1.init(n),S2.init(n);
	for (i = 1; i <= m; ++i) a[i] = i,T[ey[i]] = Merge(T[ey[i]],i);
	while (!q.empty()){
		x = S2.Find(q.front()),q.pop();
		while (T[x] && !chk(a[T[x]])) pop(T[x]);
		e = a[T[x]]; pop(T[x]); y = S2.Find(ex[e]); //y->x
		if (!S1.connect(x,y)){ S1.Merge(x,y),pre[x] = y,in[x] = e,ans += ev[e]; continue; }
		in[x] = e,ans += ev[e]; Tag(T[x],-ev[in[x]]);
		while (y ^ x){
			Tag(T[y],-ev[in[y]]),T[x] = Merge(T[x],T[y]),S2.Merge(y,x);
			pre[y] = S2.Find(pre[y]);
			y = pre[y];
		}
		q.push(x);
	}
	if (ans >= 2 * INF) cout << -1 << '\n'; else cout << ans - INF << '\n';
	return 0;
}
posted @ 2020-09-05 23:23  srf  阅读(211)  评论(0编辑  收藏  举报