老大

题目描述

因为 OB 今年拿下 4 块金牌,学校赞助扩建劳模办公室为劳模办公室群,为了体现 OI 的特色,办公室群被设计成了树形(n 个点 n − 1 条边的无向连通图),由于新建的办公室太大以至于要将奖杯要分放在两个不同的地方以便同学们丢硬币进去开光,OB 想请你帮帮他看看奖杯放在哪两个办公室使得在任意一个在劳模办公室做题的小朋友能最快地找到奖杯来开光。

一句话题意:给出一个 n 个点的树,在两个合适且不同的点放上奖杯,使得每个点到最近的奖杯距离最大值最小。

输入

第一行,一个整数 n。

接下来的 n − 1 行,每行两个数 x y

输出

一个数,表示最小的最大距离。

样例输入

8
1 2
1 3
2 4
2 5
3 6
3 7
1 8

样例输出

2

提示

对于前 60% 的数据,n ≤ 100。

对于前 80% 的数据,n ≤ 2000。

对于 80% 的数据,保证树的形态随机。

对于 100% 的数据,保证 3 ≤ n ≤ 200000。


这道题有好多种解法,把题解贴一贴~

题解

3.1 60% O(n3)

n2 枚举两个奖杯位置,再 O(n) 扫一遍看看每个位置离最近奖杯最远是多少。

3.2 80% O(n2)

考虑两个奖杯管辖的区域必定有一个边界,我们枚举这个边界,也就是一条边,其中一部

分是子树,一部分是子树外,我们只要分别求出另外两个树的直径。

3.3 树形态随机

期望树的直径很短,两个奖杯都在直径上枚举。

3.4 100% 二分答案 1 O(nlogn)

奖杯在直径上,二分答案后取离直径上离端点距离答案的点,遍历 check 一遍。

3.5 100% 二分答案 2 O(nlogn)

随便提一个节点为根,二分答案,深度最深的节点一定要被照顾到,所以最深的点往上跳

答案层即可,和其距离答案以内的点都删掉,再做一次。(我最开始的做法QAQ)

此法可以拓展到 k 个奖杯,由皮皮轩友情提供。

3.6 100% 树形 dp O(n)

在 80 分的基础上用树形 dp,记下每个点向下前三长和向上一格后不回该子树最长的路径

长度。子树内直径是前两长的和与该子树各个子树直径取 max;子树外直径是父节点向上一格

后不回该子树最长的路径长度,前两长不进入该子树的向下最长路径这三条取前两长加起来与

父节点以上的答案取 max。


思路

我使用的应该算第二种二分。

也就是先二分答案——最短距离x,再按深度从大到小枚举节点,如果发现有一个节点距最近奖杯的距离大于x,即!v[i],那么找它的父亲的父亲的父亲。。。的父亲(共x个父亲)t,在t节点放置一个奖杯,然后搜索将和它距离小于等于x的节点,标记v[i]等于1。

如果发现v[i] == 0 && cnt >= 2 就直接返回0,因为已经没有更多的奖杯可以放了。这种贪心策略很容易证明,这里不再赘述。

我的AC之路多么坎坷——

1.用了DFS,自己生成一个200000个节点的链形树,结果发现RE,怀疑可能爆栈,我改。x

2.用了BFS,然后随机生成一棵200000个节点的树,虽然过了,但是发现时间有点慢,用了clock()输出所用时间,发现用了1000+ms,可能会TLE,我再改。

3.输出 读入所用时间,发现已经是几百ms,毅然将scanf改为读优,用了一些register,降了一些复杂度,但仍然不能满足要求,我还要改。

4.怀疑BFS时直接用了queue,复杂度会倍增,于是手打队列,发现复杂度一下子减掉了一半,只有400~500+ms水平,估计没有问题,但是仍然打了对拍(其实DFS打好以后就打了对拍),没有发现错误,实际上也AC了。

给出了那些我打的代码QAQ(好艰辛)

代码

//暴力
#include<bits/stdc++.h>
using namespace std;
#define MAXN 200005 int n, x, y;
int head[MAXN], nxt[MAXN << 1], to[MAXN << 1], tot;
int dis[MAXN]; inline void Add( int x, int y ){
to[++tot] = y; nxt[tot] = head[x]; head[x] = tot;
} void dfs( int x, int fa, int d ){
dis[x] = min( dis[x], d );
for ( int i = head[x]; i; i = nxt[i] ) if ( to[i] != fa ) dfs( to[i], x, d + 1 );
} int main(){
scanf( "%d", &n );
for ( int i = 1; i < n; ++i ){
scanf( "%d%d", &x, &y ); Add( x, y ); Add( y, x );
}
int ans(0x7f7f7f7f);
for ( int i = 1; i <= n; ++i )
for ( int j = i + 1; j <= n; ++j ){
memset( dis, 0x3f, sizeof dis );
dfs( i, i, 0 );
dfs( j, j, 0 );
int cur(0);
for ( int k = 1; k <= n; ++k ) cur = max( cur, dis[k] );
ans = min( ans, cur );
}
printf( "%d\n", ans );
return 0;
}
//深搜
#include<bits/stdc++.h>
using namespace std;
#define MAXN 200005 int n, x, y;
int head[MAXN], nxt[MAXN << 1], to[MAXN << 1], tot;
int dep[MAXN], o[MAXN], f[MAXN];
int v[MAXN]; bool cmp( int x, int y ){
return dep[x] > dep[y];
} inline void Add( int x, int y ){
to[++tot] = y; nxt[tot] = head[x]; head[x] = tot;
} void DFS( int x, int fa, int d ){
dep[x] = d; f[x] = fa;
for ( int i = head[x]; i; i = nxt[i] )
if ( to[i] != fa ) DFS( to[i], x, d + 1 );
} void dfs( int x, int fa, int d, int maxd ){
if ( d > maxd ) return;
v[x] = 1;
for ( int i = head[x]; i; i = nxt[i] )
if ( to[i] != fa ) dfs( to[i], x, d + 1, maxd );
} bool check( int x ){
int cur(0); memset( v, 0, sizeof v );
for ( int i = 1; i <= n; ++i ){
if ( !v[o[i]] ){
int t(o[i]);
for ( int j = 1; j <= x; ++j ) t = f[t];
cur++;
if ( cur > 2 ) return 0;
dfs( t, t, 0, x );
}
}
return 1;
} int main(){
scanf( "%d", &n );
for ( int i = 1; i < n; ++i ){
scanf( "%d%d", &x, &y ); Add( x, y ); Add( y, x );
}
DFS( 1, 1, 1 );
for ( int i = 1; i <= n; ++i ) o[i] = i;
sort( o + 1, o + n + 1, cmp );
int l(1), r(200000), mid, ans(-1);
while( l <= r ){
mid = ( l + r ) >> 1;
if ( check( mid ) ) r = mid - 1, ans = mid;
else l = mid + 1;
}
printf( "%d\n", ans );
return 0;
}
//宽搜(偷懒STL)
#include<bits/stdc++.h>
using namespace std;
#define MAXN 400005 int n, x, y;
int head[MAXN], nxt[MAXN << 1], to[MAXN << 1], tot;
int dep[MAXN], o[MAXN], f[MAXN];
int v[MAXN]; bool cmp( int x, int y ){
return dep[x] > dep[y];
} inline void Add( int x, int y ){
to[++tot] = y; nxt[tot] = head[x]; head[x] = tot;
} void BFS(){
queue<int> Q;
Q.push(1); f[1] = 1; dep[1] = 1; while( !Q.empty() ){
int t(Q.front()); Q.pop();
for ( int i = head[t]; i; i = nxt[i] )
if ( to[i] != f[t] ){
dep[to[i]] = dep[t] + 1; f[to[i]] = t; Q.push(to[i]);
}
}
} struct states{
int id, de, fa;
}; states make_st( int x, int y, int z ){
states t;
t.id = x; t.de = y; t.fa = z;
return t;
} void bfs( int x, int maxd ){
queue<states> Q;
Q.push( make_st( x, 0, x ) );
while( !Q.empty() ){
int t(Q.front().id), d(Q.front().de), fth(Q.front().fa);
Q.pop(); v[t] = 1;
if ( d >= maxd ) continue;
for ( int i = head[t]; i; i = nxt[i] )
if ( to[i] != fth ) Q.push( make_st( to[i], d + 1, t ) );
}
} bool check( int x ){
int cur(0); memset( v, 0, sizeof v );
for ( int i = 1; i <= n; ++i ){
if ( !v[o[i]] ){
int t(o[i]);
for ( int j = 1; j <= x; ++j ) t = f[t];
cur++;
if ( cur > 2 ) return 0;
bfs( t, x );
}
}
return 1;
} int main(){
scanf( "%d", &n );
for ( int i = 1; i < n; ++i ){
scanf( "%d%d", &x, &y ); Add( x, y ); Add( y, x );
}
BFS();
for ( int i = 1; i <= n; ++i ) o[i] = i;
sort( o + 1, o + n + 1, cmp );
int l(1), r(200000), mid, ans(-1);
while( l <= r ){
mid = ( l + r ) >> 1;
if ( check( mid ) ) r = mid - 1, ans = mid;
else l = mid + 1;
}
printf( "%d\n", ans );
return 0;
}
//把STL改为手打QAQ
//最后的结果
#include<bits/stdc++.h>
using namespace std;
#define MAXN 200005
#define Reg register int n;
int head[MAXN], nxt[MAXN << 1], to[MAXN << 1], tot;
int dep[MAXN], o[MAXN], f[MAXN];
int v[MAXN]; int read(){
Reg int x(0);
Reg char c = getchar();
while ( !isdigit(c) ) c = getchar();
for ( ;isdigit(c); c = getchar() ) x = x * 10 + ( c ^ '0' );
return x;
} bool cmp( int x, int y ){
return dep[x] > dep[y];
} inline void Add( int x, int y ){
to[++tot] = y; nxt[tot] = head[x]; head[x] = tot;
}
int q[MAXN]; void BFS(){
int tl(1), hd(1);
q[1] = 1; f[1] = 1; dep[1] = 1; while( tl >= hd ){
int t(q[hd]); hd++;
for ( int i = head[t]; i; i = nxt[i] )
if ( to[i] != f[t] ){
dep[to[i]] = dep[t] + 1; f[to[i]] = t; q[++tl] = to[i];
}
}
} struct states{
int id, de, fa;
}; inline states make_st( int x, int y, int z ){
states t;
t.id = x; t.de = y; t.fa = z;
return t;
} states Q[MAXN]; void bfs( int x, int maxd ){
int tl(1), hd(1);
Q[1] = make_st( x, 0, x );
while( tl >= hd ){
int t(Q[hd].id), d(Q[hd].de), fth(Q[hd].fa);
hd++; v[t] = 1;
if ( d >= maxd ) continue;
for ( int i = head[t]; i; i = nxt[i] )
if ( to[i] != fth ) Q[++tl] = make_st( to[i], d + 1, t );
}
} bool check( int x ){
int cur(0); memset( v, 0, sizeof v );
for ( Reg int i = 1; i <= n; ++i ){
if ( !v[o[i]] ){
int t(o[i]);
for ( int j = 1; j <= x; ++j ) t = f[t];
cur++;
if ( cur > 2 ) return 0;
bfs( t, x );
}
}
return 1;
} int main(){
// freopen( "ob.in", "r", stdin );
// freopen( "ob.out", "w", stdout );
scanf( "%d", &n );
Reg int x, y;
for ( Reg int i = 1; i < n; ++i ){
x = read(); y = read();
Add( x, y ); Add( y, x );
}
BFS();
for ( Reg int i = 1; i <= n; ++i ) o[i] = i;
sort( o + 1, o + n + 1, cmp );
int l(1), r(200000), mid, ans(-1);
while( l <= r ){
mid = ( l + r ) >> 1;
if ( check( mid ) ) r = mid - 1, ans = mid;
else l = mid + 1;
}
printf( "%d\n", ans );
return 0;
}

「模拟赛 2018-11-02」T3 老大 解题报告的更多相关文章

  1. NOIP模拟赛-2018.11.7

    NOIP模拟赛 如果用命令行编译程序可以发现没加头文件之类的错误. 如果用命令行编译程序可以发现没加头文件之类的错误. 如果用命令行编译程序可以发现没加头文件之类的错误. 编译之前另存一份,听说如果敲 ...

  2. NOIP模拟赛-2018.11.6

    NOIP模拟赛 今天想着反正高一高二都要考试,那么干脆跟着高二考吧,因为高二的比赛更有技术含量(我自己带的键盘放在这里). 今天考了一套英文题?发现阅读理解还是有一些困难的. T1:有$n$个点,$m ...

  3. NOIP模拟赛-2018.11.5

    NOIP模拟赛 好像最近每天都会有模拟赛了.今天从高二逃考试跑到高一机房,然而高一也要考试,这回好像没有拒绝的理由了. 今天的模拟赛好像很有技术含量的感觉. T1:xgy断句. 好诡异的题目,首先给出 ...

  4. 【HHHOJ】ZJOI2019模拟赛(十六)4.07 解题报告

    点此进入比赛 得分: \(100+100+100=300\) 排名: \(Rank\ 1\) \(Rating\): \(+13\)(\(\frac18Rated\)) 备注: 这场比赛全是做过的原题 ...

  5. 【HHHOJ】ZJOI2019模拟赛(十二)03.03 解题报告

    点此进入比赛 得分: \(0+77+20=97\) 排名: \(Rank\ 5\) \(Rating\):\(+46\) \(T1\):[HHHOJ178]依神(点此看题面) 这套题目中的唯一一道传统 ...

  6. 【HHHOJ】ZJOI2019模拟赛(十四)03.12 解题报告

    点此进入比赛 得分: \(50+5+24=79\) 排名: \(Rank\ 2\) \(Rating\):\(+79\) \(T1\):[HHHOJ197]古明地(点此看题面) 基本上全部时间都用来想 ...

  7. 【HHHOJ】ZJOI2019模拟赛(十五)03.17 解题报告

    点此进入比赛 得分: \(42+10+14=66\) 排名: \(Rank\ 3\) \(Rating\):\(+53\) \(T1\):[HHHOJ200]稗田的梦中之梦(点此看题面) 暴力\(DF ...

  8. NOIP模拟赛-2018.10.22

    模拟赛 今天第一节课是历史,当然是不可能上的,一来到机房发现今天高二考试... 老师说以后可能还要给高一考...那还不如现在跟着做好了,毕竟在学长学姐中垫底显得没那么丢人 这套题风格挺奇怪的...为什 ...

  9. 「洛谷P1233」木棍加工 解题报告

    P1233 木棍加工 题目描述 一堆木头棍子共有n根,每根棍子的长度和宽度都是已知的.棍子可以被一台机器一个接一个地加工.机器处理一根棍子之前需要准备时间.准备时间是这样定义的: 第一根棍子的准备时间 ...

随机推荐

  1. AFNetworkingErrorDomain 错误

    AFNetworking and POST Request I'm getting this response in error.userInfo while making a POST reques ...

  2. NetBeans配置

    NetBeans下载链接:https://netbeans.org/downloads/8.2/ 选择PHP×64版本 NetBeans 安装插件Darcula LAF for NetBeansctr ...

  3. oracle函数 power(x,y)

    [功能]返回x的y次幂 [参数]x,y 数字型表达式 [返回]数字 [示例] select power(2.5,2),power(1.5,0),power(20,-1) from dual; 返回:6 ...

  4. SuperSocket从服务器端主动发起连接

    你可以从服务器端主动连接客户端, 连接建立之后的网络通信处理将和客户端主动建立连接的处理方式一样. var activeConnector = appServer as IActiveConnecto ...

  5. MySQL基础内容

    数据类型 菜鸟教程(见最下方网友整理) : https://www.runoob.com/mysql/mysql-data-types.html 其他: 1字节(byte)=8位(bit),所以dou ...

  6. Python--day62--ORM的使用

    4.Django里ORM的使用 1,手动创建数据库 2,在settings.py里面,配置数据库的连接信息 3,在项目/__init__.py告诉Django用pymysql模块代替MySQLdb(不 ...

  7. 【codeforces 761C】Dasha and Password(贪心+枚举做法)

    time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard o ...

  8. 【u232】围棋游戏

    Time Limit: 1 second Memory Limit: 128 MB [问题描述] 为了增强幼儿园小朋友的数数能力,小虎老师给了一个家庭游戏作业.让小虎那一块空的围棋盘,随机在一些方格中 ...

  9. P1092 电子表格

    题目描述 在流行的电子表格系统中(例如,在Excel中),使用如下计算方式来对列号进行计算. 第1列对应A,第2列对应B,--,第26列对应Z.然后使用两个大写英文字母来表示列:第27列对应AA,第2 ...

  10. Vue中qs插件的使用

    qs 是一个增加了一些安全性的查询字符串解析和序列化字符串的库. 在项目中使用命令行工具输入:npm install qs安装完成后在需要用到的组件中:import qs from ‘qs’具体使用中 ...