• Luogu P4654 [CEOI2017]Mousetrap


    Link
    我们以有陷阱的房子为根。
    一旦老鼠向下进入一个子树内,且管理员不帮它清理上一次走过的道路,那么它最终会被自己弄脏的走廊困在某个叶子节点。
    老鼠被困在叶子节点之后管理员的最优决策一定是先把这个叶子节点到根节点路径上的岔路口全部堵上,然后一次次把老鼠当前位置到父亲的边清理直到老鼠走到根。
    因此在老鼠向下走时管理员帮它清理上一次走过的道路一定是不优的。管理员本可以在这期间进行堵上岔路口的操作。
    那么现在情况就是老鼠先往上走一段距离,然后走进一棵子树。
    走进任意一棵子树之后的操作步数是可以dp出来的,设(f_u)表示老鼠进入了(u)的子树,然后又被赶回(u)的最小步数。
    在老鼠向下走之后管理员每次堵住当前点通向(f)值最大的子树的边一定最优。
    因此转移方程为(f_u=operatorname{2ndmax}limits_{vin son_u}(f_v)+deg_u-1)
    然后我们再处理出(sum_u)表示(u)节点到根路径上的岔路口数。
    那么老鼠第一次向下走,走到(u),然后游戏结束的最少步数为(g_u=f_u+sum_{fa_u}-[fa_u e start])
    那么现在问题就是老鼠第一次向下走会走到哪个点。
    二分答案(lim)变成判定性问答题,老鼠肯定是想找个(g_u>lim)的点走下去,而管理员就需要把这样的点封上。因为管理员在操作(lim)也会变小。
    最后如果能够全部堵上那么(lim)时间就是合法的,否则不合法。

    #include<cctype>
    #include<cstdio>
    #include<vector>
    #include<algorithm>
    const int N=1000007;
    char ibuf[1<<24],*iS=ibuf;int n,root,start,cnt,fa[N],f[N],id[N],sum[N];std::vector<int>e[N],g[N];
    int read(){int x=0;while(isspace(*iS))++iS;while(isdigit(*iS))(x*=10)+=*iS++&15;return x;}
    void dfs(int u)
    {
        int mx1=0,mx2=0;
        for(int v:e[u])
        {
    	if(v==fa[u]) continue;
    	fa[v]=u,dfs(v);
    	if(f[v]>mx1) mx2=mx1,mx1=f[v]; else if(f[v]>mx2) mx2=f[v];
        }
        f[u]=mx2+(int)e[u].size()-1;
    }
    int check(int lim)
    {
        for(int i=cnt,res=0;i>1;--i)
        {
    	++res;int now=0;
    	for(int v:g[id[i]])
    	    if(v-now>lim)
    	    {
    		if(!res||!lim)return 0;
    		--lim,--res,++now;
    	    }
        }
        return 1;
    }
    int find()
    {
        int l=0,r=n,mid;
        while(l<=r) mid=(l+r)/2,check(mid)? r=mid-1:l=mid+1;
        return l;
    }
    int main()
    {
        fread(ibuf,1,1<<24,stdin);
        n=read(),root=read(),start=read(),e[root].push_back(0);
        for(int i=1,u,v;i<n;++i) u=read(),v=read(),e[u].push_back(v),e[v].push_back(u);
        dfs(root);
        for(int u=start;u;u=fa[u]) id[++cnt]=u;
        std::reverse(id+1,id+cnt+1);
        for(int i=1;i<=cnt;++i) sum[i]=sum[i-1]+(int)e[id[i]].size()-2+(i==cnt);
        for(int i=cnt,u;u=id[i],i;--i) for(int v:e[u]) if(v!=id[i-1]&&v!=id[i+1]) g[u].push_back(f[v]+sum[i]);
        printf("%d",find());
    }
    
  • 相关阅读:
    四轴PID思路整理
    STM32输入捕获TIM2四通道
    四轴和遥控器的对应
    四层板学习(二)
    四层板学习(一)布线前的准备
    冲突的处理方法
    散列表
    重设置电脑时间
    深圳销量统计源码分析
    源码分析
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/13024245.html
Copyright © 2020-2023  润新知