zoukankan      html  css  js  c++  java
  • 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 << '
    '; else cout << ans - INF << '
    ';
    	return 0;
    }
    
  • 相关阅读:
    java 字符串split有很多坑,使用时请小心!!
    Java并发编程:线程池的使用
    java自带线程池和队列详细讲解
    merge into的用法
    Oracle中如何使用REGEXP_SUBSTR函数
    oracle分组统计某列逗号隔开数据
    oracle一列中的数据有多个手机号码用逗号隔开,我如何分别取出来?
    css box-shadow使用---转
    201706问题记录
    201705问题记录
  • 原文地址:https://www.cnblogs.com/s-r-f/p/13620264.html
Copyright © 2011-2022 走看看