BJ 集训测试11 捕鱼
2018-03-27 00:09
302 查看
http://www.elijahqi.win/archives/2792
相当于两个人在博弈 先手可以删除一条边或者添加一条边 后手可以走一条边 然后再删除一条边 给定起点终点 后手使得先手操作数最多 先手使得操作数最少 求先手的操作数最少是?
考虑将终点作为树根,如果不在叶子节点那么显然我会把代价最大的那条边封死然后后手就会走代价次大的那个边 同时我还需要用1的代价重新使得他回来那么凑巧 代价就是这个点的叶子数假如我只有一个 那么答案显然是1 因为我直接封死他即可
考虑起点和终点相邻的情况下后手一定往远离起点的方向走那么我们可以在o(n)的时间内dfs解决
如果没有直接相连怎么办我可以二分一下我答案的最大值 然后每次计算的时候 假设这个点在b~a的路径上且该点为u 即u是路径上某一点子树里的点 如果我在到达他之前需要封的点加上该点需要操作数大于我的二分答案了就说明这个一定得封死要不然答案肯定比Mid大
相当于两个人在博弈 先手可以删除一条边或者添加一条边 后手可以走一条边 然后再删除一条边 给定起点终点 后手使得先手操作数最多 先手使得操作数最少 求先手的操作数最少是?
考虑将终点作为树根,如果不在叶子节点那么显然我会把代价最大的那条边封死然后后手就会走代价次大的那个边 同时我还需要用1的代价重新使得他回来那么凑巧 代价就是这个点的叶子数假如我只有一个 那么答案显然是1 因为我直接封死他即可
考虑起点和终点相邻的情况下后手一定往远离起点的方向走那么我们可以在o(n)的时间内dfs解决
如果没有直接相连怎么办我可以二分一下我答案的最大值 然后每次计算的时候 假设这个点在b~a的路径上且该点为u 即u是路径上某一点子树里的点 如果我在到达他之前需要封的点加上该点需要操作数大于我的二分答案了就说明这个一定得封死要不然答案肯定比Mid大
#include<cstdio> #include<algorithm> #define N 1000010 using namespace std; inline char gc(){ static char now[1<<16],*S,*T; if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;} return *S++; } inline int read(){ int x=0;char ch=gc(); while(ch<'0'||ch>'9') ch=gc(); while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=gc(); return x; } struct node{ int y,next; }data[N<<1]; int fa ,h ,leaf ,w ,a,b,n,num; inline void dfs(int x){ int cnt=0,mx1=0,mx2=0; for (int i=h[x];i;i=data[i].next){ int y=data[i].y;if (y==fa[x]) continue;fa[y]=x;++cnt;dfs(y); if (w[y]>mx1) mx2=mx1,mx1=w[y];else if (w[y]>mx2) mx2=w[y]; }w[x]=(leaf[x]=cnt)+mx2; } inline bool check(int md){ int last=a,x=a,all=1,ans=0,sum=0; for (int i=a;i!=b;i=fa[i]) all+=leaf[i]-1; while(x!=b){int ans1=0;++sum; for (int i=h[x];i;i=data[i].next){ int y=data[i].y;if (y==last||y==fa[x]) continue; if (all+w[y]+ans>md) ++ans1,--sum;if(sum<0) return 0; }ans+=ans1;all-=leaf[x]-(last!=x);last=x;x=fa[x];if (ans>md) return 0; }return ans<=md?1:0; } int main(){ freopen("t3.in","r",stdin); n=read();b=read();a=read(); for (int i=1;i<n;++i){ int x=read(),y=read(); data[++num].y=y;data[num].next=h[x];h[x]=num; data[++num].y=x;data[num].next=h[y];h[y]=num; } dfs(b);int l=0,r=n<<1; while(l<=r){ int mid=l+r>>1; if(check(mid)) r=mid-1;else l=mid+1; }printf("%d\n",l); return 0; }
相关文章推荐
- BJ 集训测试11 level&& codeforces 700E
- BJ 集训测试11 flow
- BJ 集训测试13 平行
- BJ 集训测试14 bird
- BJ 集训测试7 Mythological VII
- BJ 集训测试10 城市
- BJ 集训测试7 A模型
- BJ 集训8 测试 B 新访问计划
- BJ 集训测试6 求和
- BJ 集训测试9 Problem C King
- BJ 集训测试10 序列
- BJ 集训测试13 钢琴
- BJ 集训测试8 Problem C 插线板
- BJ 集训测试14 pow
- BJ 集训测试9 draw
- BJ 集训测试12 同构
- BJ 集训测试12 coin
- 奋战吧!测试11加油!八组加油!
- iOS 11开发教程(九)iOS11数据线连接真机测试
- 【2016北京集训测试赛(十六)】 River (最大流)