传送门

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

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

答案显然满足二分性.对于老鼠,如果有一种策略使得花费步数\(>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\neq 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\n",ans);
return 0;
}

luogu P4654 [CEOI2017]Mousetrap的更多相关文章

  1. [CEOI2017]Mousetrap

    P4654 [CEOI2017]Mousetrap 博弈论既视感 身临其境感受耗子和管理的心理历程. 以陷阱为根考虑.就要把耗子赶到根部. 首先一定有解. 作为耗子,为了拖延时间,必然会找到一个子树往 ...

  2. LOJ2482 CEOI2017 Mousetrap 二分答案、树形DP

    传送门 表示想不到二分答案qwq 将树看作以陷阱为根.先考虑陷阱和起始点相邻的情况,此时老鼠一定会往下走,而如果管理者此时不做操作,那么一定会选择让操作次数变得最大的一棵子树.设\(f_i\)表示当前 ...

  3. Solution -「CEOI 2017」「洛谷 P4654」Mousetrap

    \(\mathscr{Description}\)   Link.   在一个含 \(n\) 个结点的树形迷宫中,迷宫管理者菈米莉丝和一只老鼠博弈.老鼠初始时在结点 \(y\),有且仅有结点 \(x\ ...

  4. Luogu 魔法学院杯-第二弹(萌新的第一法blog)

    虽然有点久远  还是放一下吧. 传送门:https://www.luogu.org/contest/show?tid=754 第一题  沉迷游戏,伤感情 #include <queue> ...

  5. luogu p1268 树的重量——构造,真正考验编程能力

    题目链接:http://www.luogu.org/problem/show?pid=1268#sub -------- 这道题费了我不少心思= =其实思路和标称毫无差别,但是由于不习惯ACM风格的题 ...

  6. [luogu P2170] 选学霸(并查集+dp)

    题目传送门:https://www.luogu.org/problem/show?pid=2170 题目描述 老师想从N名学生中选M人当学霸,但有K对人实力相当,如果实力相当的人中,一部分被选上,另一 ...

  7. [luogu P2647] 最大收益(贪心+dp)

    题目传送门:https://www.luogu.org/problem/show?pid=2647 题目描述 现在你面前有n个物品,编号分别为1,2,3,--,n.你可以在这当中任意选择任意多个物品. ...

  8. Mousetrap - Keyboard shortcuts in Javascript

    Mousetrap is a simple library for handling keyboard shortcuts in Javascript. It is around 2kb minifi ...

  9. Luogu 考前模拟Round. 1

    A.情书 题目:http://www.luogu.org/problem/show?pid=2264 赛中:sb题,直接暴力匹配就行了,注意一下读入和最后一句话的分句 赛后:卧槽 怎么只有40 B.小 ...

随机推荐

  1. 快速排序和二分查找(Java)

    import java.util.Arrays; public class Main { public static void main(String[] args) { int[] data = { ...

  2. C++入门经典-例5.8-使用指针函数进行运算

    1:函数指针式指向函数内存的指针,一个函数在编译时被分配给一个入口地址,这个函数的入口地址就称为函数指针.可以用一个指针变量指向函数,然后通过该指针变量调用此函数. 一个函数可以返回一个整数型值.字符 ...

  3. 20175215 2018-2019-2 第四周Java课程学习总结

    第五章学习内容 1.子类的继承性 (1)子类和父类在同一包中的继承性 如果子类和父类在同一个包中,那么,子类自然地继承了其父类中不是private的成员变量作为自己的成员变量,并且也自然地继承了父类中 ...

  4. TCP keepalive的详解(解惑)

    TCP是面向连接的,一般情况,两端的应用程序可以通过发送和接收数据得知对端的存活. 当两端的应用程序都没有数据发送和接收时,如何判断连接是否正常呢? 这就是SO_KEEPALIVE的作用. 1. SO ...

  5. leetcode 621 任务调度器 Task Scheduler

    给定一个用字符数组表示的 CPU 需要执行的任务列表.其中包含使用大写的 A - Z 字母表示的26 种不同种类的任务.任务可以以任意顺序执行,并且每个任务都可以在 1 个单位时间内执行完.CPU 在 ...

  6. kotlin之字符串

    在kotlin 中 使用String 表示字符串类型,如下二类字符串 一 普通字符串 var s1 = "hello world" 二 保留原始格式的字符串 var s2 = &q ...

  7. 在 Android 中进程的级别有哪些?

    a) Foreground processb) Visible processc) Service processd) Background processe) Empty process

  8. 【sqlalchemy】使用正确的DB_URI却报错密码错误-密码中包含特殊符号导致

    [原因] db_password密码中含有特定字符,比如含有@ %,则把密码部分进行URL编码 [解决办法] from urllib.parse import quote_plus as urlquo ...

  9. [VBA]合并工作簿优化版

    Sub 合并工作簿数据()Dim arrDim i As Integer, j As Integer, x As IntegerDim f As String, m As String, n As S ...

  10. resultMap的使用总结

    Mybatis:resultMap的使用总结   resultMap是Mybatis最强大的元素,它可以将查询到的复杂数据(比如查询到几个表中数据)映射到一个结果集当中. resultMap包含的元素 ...