zoukankan      html  css  js  c++  java
  • NOI2020 超现实树

    NOI2020 超现实树 surreal

    目标:判定树集 (mathscr{T}) 是否 "几乎完备" 。

    其中,(mathscr{T}) "几乎完备" 当且仅当仅有有限棵树不能被树集 (mathscr{T}) 生成。

    生成定义为:将一个儿子替换为一棵树。

    (sum nle 2 imes 10^6),多次查询。

    Solution

    定义 ( extrm{grow}(mathscr{T})) 表示树集 (mathscr{T}) 的生长集合。

    首先可以发现只有那种 "链树" 是有效的(即不存在一个点同时拥有两个儿子满足他们两个子树大小都大于 (1))。

    假设一棵树 (T) 不为链树,那么不难发现无论多少棵非链树,都无法达到一棵链树可以替换得到的效果。

    所以我们保留所有的链树。

    问题等价于尝试去生成所有的链树。

    (solve(mathscr{T})) 表示树集 ({mathscr{T}}) 能否生成。

    可以发现 (mathscr{T}) 能够生成,当且仅当 (mathscr{F_l+varnothing},mathscr{F_r+varnothing},mathscr{F_l+rs},mathscr{F_r+ls}) 均能够生成。

    那么将树进行分类并递归即可。

    注意到每棵树只能递归 (dep) 次,所以总体复杂度是 (mathcal O(sum dep)),即 (mathcal O(sum n))

    代码非常好写。

    (Code:)

    #include<bits/stdc++.h>
    using namespace std ;
    #define Next( i, x ) for( register int i = head[x]; i; i = e[i].next )
    #define rep( i, s, t ) for( register int i = (s); i <= (t); ++ i )
    #define drep( i, s, t ) for( register int i = (t); i >= (s); -- i )
    #define re register
    #define vi vector<int> 
    #define pb push_back
    int gi() {
    	char cc = getchar() ; int cn = 0, flus = 1 ;
    	while( cc < '0' || cc > '9' ) {  if( cc == '-' ) flus = - flus ; cc = getchar() ; }
    	while( cc >= '0' && cc <= '9' )  cn = cn * 10 + cc - '0', cc = getchar() ;
    	return cn * flus ;
    }
    const int N = 2e6 + 5 ; 
    int n, m ; 
    vi L[N], R[N], sz[N], Nw, Id ; 
    bool check(vi S, vi nw) {
    	if( S.empty() ) return 0 ; 
    	vi Lv, Rv, Ls, Rs ;
    	vi lv, rv, ls, rs ; int flag = 0 ; 
    	for(re int i = 0; i < S.size(); ++ i) {
    		int x = S[i], u = nw[i] ; 
    		int l = L[x][u], r = R[x][u] ;
    		if( !l && !r ) flag = 1 ; 
    		if( l && sz[x][r] == 0 ) Lv.pb(x), lv.pb(l) ; 
    		if( r && sz[x][l] == 0 ) Rv.pb(x), rv.pb(r) ; 
    		if( l && sz[x][r] == 1 ) Ls.pb(x), ls.pb(l) ;
    		if( r && sz[x][l] == 1 ) Rs.pb(x), rs.pb(r) ;
    	}
    	if( flag ) return 1 ; 
    	flag = 1 ; 
    	flag &= check(Lv, lv),
    	flag &= check(Ls, ls),
    	flag &= check(Rv, rv),
    	flag &= check(Rs, rs) ;
    	return flag ; 
    }
    void Dfs(int id, int x) {
    	sz[id][x] = 1 ; int l = L[id][x], r = R[id][x] ; 
    	if(l) Dfs(id, l), sz[id][x] += sz[id][l] ; 
    	if(r) Dfs(id, r), sz[id][x] += sz[id][r] ; 
    }
    signed main()
    {
    	int T = gi() ; 
    	while( T-- ) {
    		m = gi() ; Id.clear() ; 
    		rep( i, 1, m ) {
    			n = gi() ; int l, r ; L[i].pb(0), R[i].pb(0), sz[i].pb(0) ;  
    			rep( j, 1, n ) l = gi(), r = gi(), L[i].pb(l), R[i].pb(r), sz[i].pb(0) ; 
    			Id.pb(i), Dfs(i, 1), Nw.pb(1) ; 
    		}
    		if( check(Id, Nw) ) puts("Almost Complete") ;
    		else puts("No") ;
    		rep( i, 1, m ) L[i].clear(), R[i].clear(), sz[i].clear() ;
    		Id.clear(), Nw.clear() ; 
    	}
    	return 0 ;
    } 
    
  • 相关阅读:
    JavaScript匿名函数的使用
    __construct __destory __call __get __set
    嵌入式学习
    动态加载script文件
    Android框架Volley使用:Post请求实现
    Android框架Volley使用:Get请求实现
    安卓开发笔记(三十五):Cardview的简单使用
    安卓开发笔记(三十四):Material Design框架实现优美的左侧侧滑栏
    Android APK反编译技巧全讲解
    Java数据结构(一):栈
  • 原文地址:https://www.cnblogs.com/Soulist/p/13720295.html
Copyright © 2011-2022 走看看