zoukankan      html  css  js  c++  java
  • Codefoces 516D. Drazil and Morning Exercise题解

    原题链接:516D. Drazil and Morning Exercise

    题目大意:给定一棵(n)个点的树,定义(f_x=max_{i=1}^n ext{dist}(x,i))(q)次询问,每次给出一个(l),求树上一个最大的连通块(S),使得(max_{x in S}-min_{x in S}leq l),求最大的连通块大小。


    题解:首先,看到(q leq 50),很容易想到这是一个时间复杂度在(O(nq))左右的算法,然后注意到对于每一个点,离它最远的点一定是直径的两端点之一,所以(f_x)可以在(O(n))的时间内求出。接下来考虑对于每一个询问怎么处理。先给出一个算法,然后再解释这个算法为什么是正确的:将所有点按照(f_x)从大到小排序,然后用 two-pointers 从大到小扫,令 two-pointers 的两个端点为(i,j(f_i leq f_j)),第(i)个点把与它相邻的且之前访问过的点并进去(或者说是与它相邻的(f)值更大的点),对于(f_j-l>f_i)(j)这个点直接删掉。

    好了,为什么这么做是正确的呢?我们考虑这棵树如果是以任意一条直径的中点为根,那么对于每一个节点,它的孩子节点的(f)值一定比它大(证明的话,随便画一画应该就可以了),那么每次当前节点被删掉时,以它为根的子树一定被删空了,所以所得的点是一定联通的。

    接下来是代码:

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    template<typename Elem>
    void read(Elem &a){
    	a=0;
    	char c=getchar();
    	while(c<'0'||c>'9'){
    		c=getchar();
    	}
    	while(c>='0'&&c<='9'){
    		a=(a<<1)+(a<<3)+(c^48);
    		c=getchar();
    	}
    }
    const int Maxn=100000;
    typedef long long ll;
    int head[Maxn+5],arrive[Maxn<<1|5],val[Maxn<<1|5],nxt[Maxn<<1|5],tot;
    void add_edge(int from,int to,int value){
    	arrive[++tot]=to;
    	val[tot]=value;
    	nxt[tot]=head[from];
    	head[from]=tot;
    }
    int n,q;
    ll f[Maxn+5];
    ll dis[Maxn+5];
    int root;
    int id[Maxn+5];
    int fa[Maxn+5],sz[Maxn+5];
    bool vis[Maxn+5];
    void init_dfs(int u,int fa){
    	f[u]=max(f[u],dis[u]);
    	for(int i=head[u];i;i=nxt[i]){
    		int v=arrive[i];
    		if(v==fa){
    			continue;
    		}
    		dis[v]=dis[u]+val[i];
    		init_dfs(v,u);
    	}
    }
    bool cmp(int p,int q){
    	return f[p]>f[q];
    }
    int find(int x){
    	if(fa[x]==x){
    		return x;
    	}
    	return fa[x]=find(fa[x]);
    }
    void merge(int x,int y){
    	int fa_x=find(x),fa_y=find(y);
    	if(fa_x==fa_y){
    		return;
    	}
    	fa[fa_y]=fa_x;
    	sz[fa_x]+=sz[fa_y];
    }
    int main(){
    	read(n);
    	int u,v,w;
    	for(int i=1;i<n;i++){
    		read(u),read(v),read(w);
    		add_edge(u,v,w);
    		add_edge(v,u,w);
    	}
    	dis[1]=0;
    	root=1;
    	init_dfs(root,0);
    	for(int i=1;i<=n;i++){
    		if(dis[i]>dis[root]){
    			root=i;
    		}
    	}
    	dis[root]=0;
    	init_dfs(root,0);
    	for(int i=1;i<=n;i++){
    		if(dis[i]>dis[root]){
    			root=i;
    		}
    	}
    	dis[root]=0;
    	init_dfs(root,0);
    	for(int i=1;i<=n;i++){
    		if(f[i]<f[root]){
    			root=i;
    		}
    	}
    	for(int i=1;i<=n;i++){
    		id[i]=i;
    	}
    	sort(id+1,id+1+n,cmp);
    	read(q);
    	int ans;
    	ll l;
    	for(int i=1;i<=q;i++){
    		ans=1;
    		read(l);
    		for(int j=1;j<=n;j++){
    			fa[j]=j;
    			sz[j]=1;
    			vis[j]=0;
    		}
    		for(int j=1,k=1;j<=n;j++){
    			while(k<j&&f[id[k]]-f[id[j]]>l){
    				sz[find(id[k])]--;
    				k++;
    			}
    			vis[id[j]]=1;
    			for(int to=head[id[j]];to;to=nxt[to]){
    				int v=arrive[to];
    				if(!vis[v]){
    					continue;
    				}
    				merge(id[j],v);
    			}
    			ans=max(ans,sz[find(id[j])]);
    		}
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    java语言实现堆排序
    堆排序
    静态分派
    谈mysql优化
    Unity2017.1官方UGUI文档翻译——Canvas
    Unity2017.1官方UGUI文档翻译——Rect Transform
    Unity2017.1官方UGUI文档翻译——Rich Text
    Unity2017.1官方UGUI文档翻译——Auto Layout
    Unity2017.1官方UGUI文档翻译——Animation Integration
    Unity2017.1官方UGUI文档翻译——Interaction Components
  • 原文地址:https://www.cnblogs.com/withhope/p/12381641.html
Copyright © 2011-2022 走看看