题目描述
有一个有 n n n 个房间和 n − 1 n-1 n−1 条走廊的迷宫,保证任意两个房间可以通过走廊互相到达,换句话说,这个迷宫的结构是一棵树。
一个老鼠被放进了迷宫,迷宫的管理者决定和老鼠做个游戏。
一开始,有一个房间被放置了陷阱,老鼠出现在另一个房间。老鼠可以通过走廊到达别的房间,但是会弄脏它经过的走廊。老鼠不愿意通过脏的走廊。
每个时刻,管理者可以进行一次操作:堵住一条走廊使得老鼠不能通过,或者擦干净一条走廊使得老鼠可以通过。然后老鼠会通过一条干净的并且没被堵住的走廊到达另一个房间。只有在没有这样的走廊的情况下,老鼠才不会动。一开始所有走廊都是干净的。管理者不能疏通已经被堵住的走廊。
现在管理者希望通过尽量少的操作将老鼠赶到有陷阱的房间,而老鼠则希望管理者的操作数尽量多。请计算双方都采取最优策略的情况下管理者需要的操作数量。
注意:管理者可以选择在一些时刻不操作。
输入输出格式
输入格式:
第一行三个空格隔开的正整数数 n,t,mn,t,m。分别代表房间的个数,陷阱房的编号和老鼠起始房间的编号。
接下来 n − 1 n-1 n−1 行,每行两个空格隔开的整数 a i , b i a_i,b_i ai,bi ,表示有一条走廊连接编号为 a i a_i ai 和 b i b_i bi 的房间。
输出格式:
输出一行包含一个整数,表示双方都采取最优策略的情况下,管理者需要的操作数量。
思路
本来做Chase的时候就有把CEOI2017做完的想法,结果咕咕了。然后考试又考了一道,QwQ。痛下决心一定要做完。
题目较难, 题解就贴这位巨佬的。
想了很久。我的想法跟这个老哥很像,但我一开始觉得老鼠向上爬只会去 f f f值最大的子树,就直接把答案算成该子树的 f f f值。然后,LOJ的数据60+。
反例就是,管理者再上方封路后,老鼠走次小子树(吗)。
代码
#include<cstdio>
#include<string>
#define R_ register
inline int read() {
int ret=0,f=1,ch=getchar();
for (; !isdigit(ch); ch=getchar()) if (ch=='-') f=-f;
for (; isdigit(ch); ch=getchar()) ret=ret*10+ch-48;
return ret*f;
}
const int maxn=2e6+5;
int tot,top,son[maxn],nxt[maxn],lnk[maxn],rod[maxn];
int N,T,S,Ans,f[maxn],fa[maxn],deg[maxn],sum[maxn],vis[maxn];
inline void add_edge(int x,int y) {
son[++tot]=y,nxt[tot]=lnk[x],lnk[x]=tot,++deg[x];
son[++tot]=x,nxt[tot]=lnk[y],lnk[y]=tot,++deg[y];
}
void Build(int x,int pre=0) {
R_ int k=lnk[x],v,Max1=0,Max2=0;
for (; v=son[k],k; k=nxt[k]) if (v^pre)
if (fa[v]=x,Build(v,x),f[v]>=Max1) Max2=Max1,Max1=f[v];
else if (f[v]>Max2) Max2=f[v];
f[x]=Max2+deg[x]-1;
}
inline bool check(int res) {
int cnt=0,tmp;
for (R_ int i=1,k,v; i<=top; ++i) {
for (tmp=0,k=lnk[rod[i]]; v=son[k]; k=nxt[k])
if (v^rod[i+1]&&v^rod[i-1]&&sum[i]+f[v]+1-(i!=1)>res) ++tmp;
cnt+=tmp,res-=tmp;
if (res<0||cnt>i) return 0;
}
return 1;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("trap.in","r",stdin);
freopen("trap.out","w",stdout);
#endif
R_ int i,L=0,R=1e8,mid;
for (N=read(),T=read(),S=read(),i=1; i<N; ++i) add_edge(read(),read());
for (Build(T),f[T]=0,i=S; i; i=fa[i]) rod[++top]=i;
for (i=top-1; i; i--) sum[i]=sum[i+1]+deg[rod[i]]-2;
for (; L<=R; ) check(mid=L+R>>1)?Ans=mid,R=mid-1:L=mid+1;
return printf("%d\n",Ans),0;
}