zoukankan      html  css  js  c++  java
  • Solution: 题解 CF1029E Tree with Small Distances

    核心思想:贪心

    先将树转化为以(1)为根的有根树

    考虑如果想要连上一个点(u),并且(u)的所有子树都已经通过其他方式连上了

    那么就有三种方法:

    1. 连上(u)自己,那么可以顺势连上(u)的父亲(f_u)

    2. 连上(u)的一个儿子,那么除了连上(u)以外没有任何效果

    3. 连上(u)的父亲(f_u),那么(f_u)的所有儿子都可以顺带连上

    综上,连上(f_u)是贪心最优的

    给每一个点(u)一个深度(d_u),其中(d_1=0)

    为了保证(u)的所有子树都连上,可以建以(d_u)为键值的大根堆,把所有(d_u>2)(u)丢进去

    每次弹出一个(u),就把(f_u)连上,即将(f_u)及其周围的点打上标记

    如果弹出的(u)打过了标记,直接忽略即可

    Time complexity: (O(nlog n))

    Memory complexity: (O(n))

    细节见代码((2.82)s / (17.77)MB)

    //This program is written by Brian Peng.
    #pragma GCC optimize("Ofast","inline","no-stack-protector")
    #include<bits/stdc++.h>
    using namespace std;
    #define Rd(a) (a=read())
    #define Gc(a) (a=getchar())
    #define Pc(a) putchar(a)
    int read(){
    	register int x;register char c(getchar());register bool k;
    	while(!isdigit(c)&&c^'-')if(Gc(c)==EOF)exit(0);
    	if(c^'-')k=1,x=c&15;else k=x=0;
    	while(isdigit(Gc(c)))x=(x<<1)+(x<<3)+(c&15);
    	return k?x:-x;
    }
    void wr(register int a){
    	if(a<0)Pc('-'),a=-a;
    	if(a<=9)Pc(a|'0');
    	else wr(a/10),Pc((a%10)|'0');
    }
    signed const INF(0x3f3f3f3f),NINF(0xc3c3c3c3);
    long long const LINF(0x3f3f3f3f3f3f3f3fLL),LNINF(0xc3c3c3c3c3c3c3c3LL);
    #define Ps Pc(' ')
    #define Pe Pc('
    ')
    #define Frn0(i,a,b) for(register int i(a);i<(b);++i)
    #define Frn1(i,a,b) for(register int i(a);i<=(b);++i)
    #define Frn_(i,a,b) for(register int i(a);i>=(b);--i)
    #define Mst(a,b) memset(a,b,sizeof(a))
    #define File(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
    #define N (200010)
    int n,u,v,f[N],d[N],ans;
    bool vs[N];
    vector<int>e[N];
    struct Cmp{bool operator()(int a,int b){return d[a]<d[b];}};
    priority_queue<int,vector<int>,Cmp>q;
    void dfs(int u);
    signed main(){
    	Rd(n);
    	Frn0(i,1,n)e[Rd(u)].push_back(Rd(v)),e[v].push_back(u);
    	dfs(1);
    	while(!q.empty()){
    		u=q.top(),q.pop();
    		if(vs[u])continue;
    		vs[f[u]]=1,++ans;
    		for(int i:e[f[u]])vs[i]=1;
    	}
    	wr(ans),exit(0);
    }
    void dfs(int u){
    	if(d[u]>2)q.push(u);
    	for(int i:e[u])if(i!=f[u])f[i]=u,d[i]=d[u]+1,dfs(i);
    }
    

    接下来是优化部分

    发现时间瓶颈在于堆操作是(O(log n))

    而且事实上根本不需要堆,因为只有在dfs时进行的push()操作,之后都是弹出

    但是如果对(u)按照(d_u)排序,用sort()还是(O(nlog n))

    其实如果要生成一个按(d_u)排序的序列有(O(n))做法,那就是……

    BFS大法好!!!!!

    BFS序就是一个按照(d_u)从小到大排序的序列

    所以只要把(d_u>2)的BFS序记录下来,然后倒着做就可以了,其它操作不变

    Time complexity: (O(n))

    Memory complexity: (O(n))

    细节见代码((2.04)s / (10.11)MB)(效果不错)

    //This program is written by Brian Peng.
    #pragma GCC optimize("Ofast","inline","no-stack-protector")
    #include<bits/stdc++.h>
    using namespace std;
    #define Rd(a) (a=read())
    #define Gc(a) (a=getchar())
    #define Pc(a) putchar(a)
    int read(){
    	register int x;register char c(getchar());register bool k;
    	while(!isdigit(c)&&c^'-')if(Gc(c)==EOF)exit(0);
    	if(c^'-')k=1,x=c&15;else k=x=0;
    	while(isdigit(Gc(c)))x=(x<<1)+(x<<3)+(c&15);
    	return k?x:-x;
    }
    void wr(register int a){
    	if(a<0)Pc('-'),a=-a;
    	if(a<=9)Pc(a|'0');
    	else wr(a/10),Pc((a%10)|'0');
    }
    signed const INF(0x3f3f3f3f),NINF(0xc3c3c3c3);
    long long const LINF(0x3f3f3f3f3f3f3f3fLL),LNINF(0xc3c3c3c3c3c3c3c3LL);
    #define Ps Pc(' ')
    #define Pe Pc('
    ')
    #define Frn0(i,a,b) for(register int i(a);i<(b);++i)
    #define Frn1(i,a,b) for(register int i(a);i<=(b);++i)
    #define Frn_(i,a,b) for(register int i(a);i>=(b);--i)
    #define Mst(a,b) memset(a,b,sizeof(a))
    #define File(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
    #define N (200010)
    int n,u,v,f[N],ans,s[N],sz;
    bool vs[N];
    struct Q{int u,d;}p;
    vector<int>e[N];
    queue<Q>q;
    signed main(){
    	Rd(n),q.push({1,0});
    	Frn0(i,1,n)e[Rd(u)].push_back(Rd(v)),e[v].push_back(u);
    	while(!q.empty()){
    		p=q.front(),q.pop();
    		if(p.d>2)s[++sz]=p.u;
    		for(int i:e[p.u])if(i!=f[p.u])f[i]=p.u,q.push({i,p.d+1});
    	}
    	Frn_(i,sz,1){
    		if(vs[s[i]])continue;
    		vs[f[s[i]]]=1,++ans;
    		for(int j:e[f[s[i]]])vs[j]=1;
    	}
    	wr(ans),exit(0);
    }
    
  • 相关阅读:
    git和github的使用
    C语言 -- 链表操作
    数据结构之表达式求值(C++版)
    数据结构之一元多项式加法(C++版)
    数据结构之邻接矩阵(C++版)
    数据结构之二叉树,赫夫曼树(C++版)
    数据结构之循环队列(C++版)
    数据结构之顺序栈(C++版)
    数据结构之单链表(C++版)
    数据结构之顺序表(C++版)
  • 原文地址:https://www.cnblogs.com/BrianPeng/p/12284707.html
Copyright © 2011-2022 走看看