zoukankan      html  css  js  c++  java
  • 【NOIP2018】赛道修建(正解)

    NOIP题目怎么都好长
    使用m条各自无边重叠的边覆盖一棵树的一部分
    要求最大化这些边的最短长度
    

    考场上高性价比的做法:点我

    最大化最短,这种一看就是二分答案啦……

    参考上面的高性价比部分分做法,我们可以把可用的边分为两类:

    一类是连接到当前子树的根的路径长度(Dis[u])

    一类是当前子树中的路径(ans[u])

    在一个子树中,我们可以把短的路径尽可能合并成长路径来统计答案

    于是只需要两遍二分即可

    代码:

    #include<bits/stdc++.h>
    #define N 50005
    using namespace std;
    
    int n,m,u,v,w;
    
    struct Edge
    {
    	int next,to,dis;
    }edge[N<<1];
    int cnt=0,head[N];
    
    inline void add_edge(int from,int to,int dis)
    {
    	edge[++cnt].next=head[from];
    	edge[cnt].to=to;
    	edge[cnt].dis=dis;
    	head[from]=cnt;
    }
    
    template<class T>inline void read(T &res)
    {
    	char c;T flag=1;
    	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
    	while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
    }
    
    bool vis[N];
    int fa[N],len[N],Dis[N],ans[N];
    int cal(int num,int limit)
    {
    	int p=1,res=0;
    	for(register int i=num;i>p;--i)
    	{
    		if(vis[i]) continue;
    		while(p<i&&(len[p]+len[i]<limit||vis[p])) p++;
    		if(p<i&&!vis[p]&&len[p]+len[i]>=limit) res++;
    		p++;
    	}
    	return res;
    }
    
    void dfs(int u,int limit)
    {
    	ans[u]=0;
    	for(register int i=head[u];i;i=edge[i].next)
    	{
    		int v=edge[i].to;
    		if(v==fa[u]) continue;
    		fa[v]=u;
    		Dis[v]=edge[i].dis;
    		dfs(v,limit);
    		ans[u]+=ans[v];
    	}
    	int num=0;
    	for(register int i=head[u];i;i=edge[i].next)
    	{
    		int v=edge[i].to;
    		if(v==fa[u]) continue;
    		len[++num]=Dis[v];
    	}
    	if(num)
    	{
    		sort(len+1,len+num+1);
    		len[0]=0;
    		int w=cal(num,limit);
    		ans[u]+=w;
    		int L=0,R=num,res;
    		while(L<=R)
    		{
    			int Mid=(L+R)>>1;
    			vis[Mid]=1;
    			if(cal(num,limit)==w) res=Mid,L=Mid+1;
    			else R=Mid-1;
    			vis[Mid]=0;
    		}
    		Dis[u]+=len[res];
    	}
    	if(Dis[u]>=limit) Dis[u]=0,ans[u]++;
    }
    
    bool check(int x)
    {
    //	cout<<"now is checking: "<<x<<endl;
    	memset(ans,0,sizeof(ans));
    	memset(Dis,0,sizeof(Dis));
    	int num=0;
    	dfs(1,x);
    	if(ans[1]>=m) return true;
    	return false;
    }
    
    int main()
    {
    	int l=1,r=0;
    	read(n);read(m);
    	for(register int i=1;i<=n-1;++i)
    	{
    		read(u);read(v);read(w);
    		add_edge(u,v,w);
    		add_edge(v,u,w);
    		r+=w;
    	}
    	int ans;
    	while(l<=r)
    	{
    		int mid=(l+r)>>1;
    		if(check(mid)) ans=mid,l=mid+1;
    		else r=mid-1;
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    基于微服务架构的RBAC权限管理系统
    用C#实现基于(OpenId Connect)的单点登录与RBAC权限验证(SSO,OIDC,RBAC)
    量化分析基础
    Ocelot 发现服务总是失败的解决办法
    windows 下安装 theano 及配置 gpu
    python scrapy 爬虫 初学
    layer弹出层框架alert与msg详解
    Workerman-文件监控-牛刀小试
    ECharts 初体验
    实验楼 linux 学习
  • 原文地址:https://www.cnblogs.com/tqr06/p/11795032.html
Copyright © 2011-2022 走看看