• luogu P4654 [CEOI2017]Mousetrap


    传送门

    这里把终点设为根方便后续处理,那么目标就是要让老鼠走到根

    首先考虑老鼠动不了的情况,这种情况下可以把从这个点到终点路径上的分支堵住,然后再疏通路径上的走过的边,可以发现这是这种情况下最优的决策.在这种情况下,老鼠一定是先往上走一段距离(也可能不走),然后走进某个分支的子树,再被赶到终点.

    答案显然满足二分性.对于老鼠,如果有一种策略使得花费步数(>mid)那么(mid)就不合法.所以可以从起点(start)往上走,每到一个点看有没有分支满足这个条件.所以还要知道进入一个子树后的花费步数,记为(f_x),转移的话,首先应该把(f)最大的儿子堵住,然后老鼠走进次大的儿子,剩下的儿子在老鼠被困住时堵住就行了,所以(f_x=|son of x|-[|son of x|>1]+f_{x2}(son of x={x1,x2,...},f_{x1}>f_{x2}>f_{x3}...)+1).

    如果进入某个分支子树,那么首先对于当前点,要把其他分支堵住,然后要把祖先的分支也堵住,所以再记分支数量(s_x=sum_{y is the ancestor of x,y eq root} |son of y|-[y!=start]),以及走入某个点以后到结束的操作步数(g_x=f_x+s_{fa_x}-1).走到某个点,如果有(g_x>mid)的儿子,就要尽量消耗能用的操作次数堵住,这个能用次数初始为(1),每次往上走一个点就(+1).如果还有这样的(g_x)就不合法.要注意每次向上走之前要把(mid)减去当前层的使用过的操作次数

    // luogu-judger-enable-o2
    #include <bits/stdc++.h>
    #define LL long long
    
    using namespace std;
    const int N=1e6+10;
    LL rd()
    {
        LL x=0,w=1;char ch=0;
        while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
        return x*w;
    }
    int to[N<<1],nt[N<<1],hd[N],tot=1;
    void add(int x,int y)
    {
        ++tot,to[tot]=y,nt[tot]=hd[x],hd[x]=tot;
        ++tot,to[tot]=x,nt[tot]=hd[y],hd[y]=tot;
    }
    int n,rt,fa[N],sz[N],f[N],g[N],ans;
    int st[N],tp;
    void dfs(int x)
    {
        for(int i=hd[x];i;i=nt[i])
        {
            int y=to[i];
            if(y==fa[x]) continue;
            fa[y]=x,dfs(y);
        }
        tp=0;
        for(int i=hd[x];i;i=nt[i])
        {
            int y=to[i];
            if(y==fa[x]) continue;
            st[++tp]=f[y];
        }
        sz[x]=tp;
        sort(st+1,st+tp+1);
        f[x]+=tp-(tp>1)+st[tp-1]+1;
    }
    bool ck(int mid,int xx)
    {
        int cn=1,la=0,dt=0;
        while(xx!=rt)
        {
            st[tp=0]=sz[fa[xx]];
            for(int i=hd[xx];i;i=nt[i])
            {
                int y=to[i];
                if(y==fa[xx]||y==la) continue;
                st[++tp]=g[y];
            }
            st[0]+=tp;
            sort(st+1,st+tp+1);
            while(tp>0&&cn>0&&st[tp]>mid) --tp,--cn,++dt;
            if(st[tp]>mid) return 0;
            mid-=dt,dt=0,la=xx,xx=fa[xx],++cn;
        }
        return 1;
    }
    
    int main()
    {
        n=rd(),rt=rd();
        int x=rd(),la=0;
        for(int i=1;i<n;++i) add(rd(),rd());
        dfs(rt);
        tp=0;
        int xx=x;
        while(xx!=rt) st[++tp]=xx,xx=fa[xx];
        --sz[st[tp]];
        for(int i=tp-1;i;--i) sz[st[i]]+=sz[st[i+1]]-1;
        ++sz[st[1]];
        sz[rt]=0;
        xx=x;
        while(xx!=rt)
        {
            for(int i=hd[xx];i;i=nt[i])
            {
                int y=to[i];
                if(y==fa[xx]||y==la) continue;
                g[y]=f[y]+sz[xx]-1;
            }
            la=xx,xx=fa[xx];
        }
        int l=0,r=n;
        while(l<=r)
        {
            int mid=(l+r)>>1;
            if(ck(mid,x)) ans=mid,r=mid-1;
            else l=mid+1;
        }
        printf("%d
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    scrapy爬虫爬取小姐姐图片(不羞涩)
    scrapy爬虫登录edusrc查看漏洞列表
    代码审计【根据功能点定向审计】BugFree ZSWin重装案例
    645-2007协议解析
    最近总结
    防爆zigbee模块
    物联网卡余额管理软件更新
    激光+紫外催化控制器
    modbus转edp协议
    modbus转mqtt工具
  • 原文地址:https://www.cnblogs.com/smyjr/p/11110880.html
Copyright © 2020-2023  润新知