#195 game(动态规划+二分)
考虑第一问的部分分。显然设f[i]为i子树从根开始扩展的所需步数,考虑根节点的扩展顺序,显然应该按儿子子树所需步数从大到小进行扩展,将其排序即可。
要做到n=3e5,考虑换根dp。计算某点答案时先将其在父亲中的贡献去掉,然后用和之前同样的方法做即可。冷静一下也没什么复杂的。
第二问注意到两个点扩展出来的点集是不相交的,枚举一条断边,就可以做到n2logn。显然断边的位置可以二分。就是nlog2n了。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define N 300010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
int x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
int n,a,b,p[N],f[N],pos[N],fa[N],id[N],e[N],t,ans=N,root;
struct data2
{
int x,y;
bool operator <(const data2&a) const
{
return x<a.x;
}
}q[N];
vector<data2> Q[N];
vector<int> pre[N],suf[N];
bool flag[N<<1];
struct data{int to,nxt;
}edge[N<<1];
void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
void dfs(int k,int from)
{
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=from&&!flag[i]) dfs(edge[i].to,k);
int cnt=0;
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=from&&!flag[i]) q[++cnt].x=f[edge[i].to],q[cnt].y=edge[i].to;
sort(q+1,q+cnt+1);reverse(q+1,q+cnt+1);
if (k==1) for (int i=1;i<=cnt;i++) Q[1].push_back((data2){q[i].x+i,q[i].y}),pos[q[i].y]=i-1;
f[k]=0;for (int i=1;i<=cnt;i++) f[k]=max(f[k],q[i].x+i);
}
int calc(int root){dfs(root,root);return f[root];}
void getans(int k,int from)
{
ans=min(ans,f[k]);
int s=Q[k].size();
pre[k].push_back(Q[k][0].x);
for (int j=1;j<s;j++) pre[k].push_back(Q[k][j].x);
for (int j=1;j<s;j++) pre[k][j]=max(pre[k][j],pre[k][j-1]);
if (s)
{
suf[k].push_back(Q[k][s-1].x);
for (int j=s-2;j>=0;j--) suf[k].push_back(Q[k][j].x);
for (int j=1;j<s;j++) suf[k][j]=max(suf[k][j],suf[k][j-1]);
reverse(suf[k].begin(),suf[k].end());
}
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=from)
{
int cnt=0,x=edge[i].to,tmp=f[k];
//f[k]去掉edge[i].to后的答案
f[k]=0;
if (pos[x]>0) f[k]=pre[k][pos[x]-1];
if (pos[x]+1<s) f[k]=max(f[k],suf[k][pos[x]+1]-1);
for (int j=p[x];j;j=edge[j].nxt)
q[++cnt].x=f[edge[j].to],q[cnt].y=edge[j].to;
sort(q+1,q+cnt+1);reverse(q+1,q+cnt+1);
f[x]=0;for (int j=1;j<=cnt;j++) f[x]=max(f[x],q[j].x+j),Q[x].push_back((data2){q[j].x+j,q[j].y}),pos[q[j].y]=j-1;
f[k]=tmp;
getans(x,k);
}
}
void getfa(int k)
{
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=fa[k])
{
fa[edge[i].to]=k;
e[edge[i].to]=i+(i&1);
getfa(edge[i].to);
}
}
int main()
{
n=read(),a=read(),b=read();
for (int i=1;i<n;i++)
{
int x=read(),y=read();
addedge(x,y),addedge(y,x);
}
dfs(1,1);
getans(1,1);
cout<<ans<<endl;ans=N;
getfa(a);int cnt=0;
int x=b;while (x!=a) id[++cnt]=x,x=fa[x];
int l=1,r=cnt;
while (l<=r)
{
int mid=l+r>>1;int x=id[mid];
flag[e[x]]=1,flag[e[x]-1]=1;
int u=calc(a),v=calc(b);
flag[e[x]]=0,flag[e[x]-1]=0;
ans=min(ans,max(u,v));
if (u>=v) l=mid+1;else r=mid-1;
}
cout<<ans;
return 0;
}
#195 game(动态规划+二分)的更多相关文章
- [LeetCode] 300. 最长上升子序列 ☆☆☆(动态规划 二分)
https://leetcode-cn.com/problems/longest-increasing-subsequence/solution/dong-tai-gui-hua-she-ji-fan ...
- 【动态规划+二分查找】POJ2533&POJ1631最长上升子序列(LIS)
POJ2533裸的LIS,时间复杂度为O(n^2) #include<iostream> #include<cstdio> using namespace std; +; in ...
- 二维动态规划&&二分查找的动态规划&&最长递增子序列&&最长连续递增子序列
题目描述与背景介绍 背景题目: [674. 最长连续递增序列]https://leetcode-cn.com/problems/longest-continuous-increasing-subseq ...
- 【LeetCode】300.最长递增子序列——暴力递归(O(n^3)),动态规划(O(n^2)),动态规划+二分法(O(nlogn))
算法新手,刷力扣遇到这题,搞了半天终于搞懂了,来这记录一下,欢迎大家交流指点. 题目描述: 给你一个整数数组 nums ,找到其中最长严格递增子序列的长度. 子序列是由数组派生而来的序列,删除(或不删 ...
- P3957 跳房子
题目描述 跳房子,也叫跳飞机,是一种世界性的儿童游戏,也是中国民间传统的体育游戏之一. 跳房子的游戏规则如下: 在地面上确定一个起点,然后在起点右侧画 n 个格子,这些格子都在同一条直线上.每个格子内 ...
- 1115 洛谷luogu最大子段和
题目描述 给出一段序列,选出其中连续且非空的一段使得这段和最大. 输入输出格式 输入格式: 第一行是一个正整数NNN,表示了序列的长度. 第二行包含NNN个绝对值不大于100001000010000的 ...
- leetcode 354. 俄罗斯套娃信封问题(二维排序有关)
题目描述 给定一些标记了宽度和高度的信封,宽度和高度以整数对形式 (w, h) 出现.当另一个信封的宽度和高度都比这个信封大的时候,这个信封就可以放进另一个信封里,如同俄罗斯套娃一样. 请计算最多能有 ...
- 简单DP入门(二) 最长上升子序列及其优化
最长上升子序列解决问题: 有N个数,求出它最长的上升子序列并输出长度. 在题里不会讲的这么直白,这个算法往往会与其他的算法混在一起使用. 在这篇文章中不会出现其他的例题,为了让大家更好的理解,我只会对 ...
- 最长递增子序列(Longest increasing subsequence)
问题定义: 给定一个长度为N的数组A,找出一个最长的单调递增子序列(不要求连续). 这道题共3种解法. 1. 动态规划 动态规划的核心是状态的定义和状态转移方程.定义lis(i),表示前i个数中以A[ ...
随机推荐
- Java 多线程(六)之Java内存模型
目录 1. 并发编程的两个问题 2 CPU 缓存模型 2.1 CPU 和 主存 2.2 CPU Cache 2.3 CPU如何通过 Cache 与 主内存交互 2.4 CPU 缓存一致性问题 3 Ja ...
- c++构造函数成员初始化中赋值和初始化列表两种方式的区别
先总结下: 由于类成员初始化总在构造函数执行之前 1)从必要性: a. 成员是类或结构,且构造函数带参数:成员初始化时无法调用缺省(无参)构造函数 b. 成员是常量或引用:成员无法赋值,只能被初始化 ...
- 一种简单有效的VBA源代码加密办法,支持64位宿主,适用于大部分VBA代码加密
原始出处:http://www.cnblogs.com/Charltsing/p/EncryptVBACode.html VBA代码加密是个老生常谈的问题,自从本人的VBA Dumper发布之后,在O ...
- 【学习总结】 小白CS成长之路
2017-9-3:入坑. 理想:敲着代码唱着歌. 现实:骨感. Step 1: 认识CS: CS大体可以分成以下几个大领域:硬件.系统.软件.网络.计算理论.计算方法. 硬 件 ---- 数字电路.集 ...
- Memcached 集群架构与memcached-session-manager
Memcached 集群架构方面的问题_知识库_博客园https://kb.cnblogs.com/page/69074/ memcached-session-manager配置 - 学习中间件调优管 ...
- 通过event记录sql
providers EventServiceProvider.php 添加 protected $listen = [ 'Illuminate\Database\Events\QueryExecute ...
- [转帖]SAP一句话入门:Plant Maintenance
SAP一句话入门:Plant Maintenance http://blog.vsharing.com/MilesForce/A618273.html PM就是Plant Maintenance(本文 ...
- Chrome 浏览器的简单设置 无痕模式 暗黑模式 自定义用户目录
1. Chrome73 新增加了暗黑模式 可以通过修改快捷方式的方式来默认开启方法如下 1.1 关闭浏览器 2.2 鼠标焦点定位到任务栏 Chrome 图标处, 并且按住shift 按键 执行右键操作 ...
- MT4用EA测试历史数据时日志出现:stopped because of stop out
今天用嘉盛的MT4测试一个EA,谁知道才走了十几天数据就完 了,看结果本金也没亏完啊,才亏了一半,而且我测的是1年的时间. 查看日志一有条警告:stopped because of stop out, ...
- day 7-7 线程池与进程池
一. 进程池与线程池 在刚开始学多进程或多线程时,我们迫不及待地基于多进程或多线程实现并发的套接字通信,然而这种实现方式的致命缺陷是:服务的开启的进程数或线程数都会随着并发的客户端数目地增多而增多,这 ...