• 【洛谷3441】[POI2006] MET-Subway(树的拓扑)


    点此看题面

    • 给定一棵(n)个点的树,求用(l)条树上路经最多能覆盖多少个点。
    • (nle10^6)

    拓扑分层

    显然路径的端点一定是叶节点(准确的说,由于这是无根树,应该是度数为(1)的节点),因为如果端点不是叶节点则路径必然可以继续拓展,答案不会变劣。

    所以有了一个从叶节点向上逐层考虑的想法,但一个致命问题就在于叶节点的深度不一定相同,如果叶节点分散在很多层的话没法进行一个统一的处理。

    这里就有一个非常奇妙的应对策略:我们不一定要让每个点的父节点与它在相邻层。

    可以假定所有叶节点在同一层,然后跑一遍拓扑排序,定义一个点所在层数是它的所有子节点中最大的层数加(1)

    接着我们再回到最开始的想法,假设第(i)层点数为(cnt_i),显然第(i)层最多有(min{cnt_i,2l})个点被覆盖,而且每一层都能达到这个上界,这应该是很容易就能构造出来的。

    代码:(O(n))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 1000000
    #define add(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y)
    using namespace std;
    int n,l,ee,lnk[N+5],deg[N+5];struct edge{int to,nxt;}e[2*N+5];
    namespace FastIO
    {
    	#define FS 100000
    	#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
    	char oc,FI[FS],*FA=FI,*FB=FI;
    	Tp I void read(Ty& x) {x=0;W(!isdigit(oc=tc()));W(x=(x<<3)+(x<<1)+(oc&15),isdigit(oc=tc()));}
    }using namespace FastIO;
    int q[N+5],rk[N+5],cnt[N+5];I void Topo()//拓扑排序
    {
    	RI i,k,H=1,T=0;for(i=1;i<=n;++i) deg[i]==1&&(q[++T]=i);//从叶节点开始拓扑
    	W(H<=T) for(++cnt[rk[k=q[H++]]],i=lnk[k];i;i=e[i].nxt) --deg[e[i].to]==1&&(rk[q[++T]=e[i].to]=rk[k]+1);//子节点中最大层数+1
    }
    int main()
    {
    	RI i,x,y;for(read(n),read(l),i=1;i^n;++i) read(x),read(y),add(x,y),add(y,x),++deg[x],++deg[y];
    	RI t=0;for(Topo(),i=0;i<=n;++i) t+=min(cnt[i],l<<1);return printf("%d
    ",t),0;//第i层选择min{cnt[i],2l}个点
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    超实用的PHP代码片段
    推荐五款优秀的PHP代码重构工具
    PHP开发搜索引擎技术全解析
    怎样成为一名PHP专家?
    PHP中该怎样防止SQL注入?
    有关PHP 10条有用的建议
    fir.im Weekly
    可能是一场很 IN 的技术分享
    fir.im Weekly
    更新日志
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu3441.html
Copyright © 2020-2023  润新知