题意:给定一个树,找出两个点,使得其他点到最近的点的距离最小

思路:

牡丹江站的B题。。可惜当时坑的不大对,最后也没写完。。

1、题解方法:

基于一个结论,答案一定在直径上(证明我不会)。。

那么,可以先求出直径,然后直接二分,二分完后o(n)判定,时间复杂度为nlogn

2、我的方法:

赛场上写的,可惜最后由于各种原因没写完,代码难度实在比题解高多了,可惜想到了就不敢在猜想其他方法了了。。

可以很容易证明,题目等价于对于删除某条边后求剩余两棵树直径,然后取一个最小的。。

那么,就可以用树形dp的方法,维护每个点为子树的前三长链(以根为起始,并且来源于不同子树),还有不经过根的前两大答案,以及以其为根的子树的答案。

先一边求完后,然后从根递推到以每个点为根成为一个树,其余为另外一棵树的答案啊。。

这样时间复杂度为o(n)

code(nlog(n)):

 #include <bits/stdc++.h>
#define M0(a, b) memset(a, 0, sizeof(int) * (b+10))
using namespace std;
const int maxn = ;
int z[maxn], inz[maxn], pos[maxn], from[maxn];
int L[maxn], R[maxn], cov[maxn];
vector<int> e[];
int n, m;
int ans, ansx, ansy; void init(){
scanf("%d", &n);
for (int i = ; i <= n; ++i)
e[i].clear();
int u, v;
for (int i = ; i < n; ++i){
scanf("%d%d", &u, &v);
e[u].push_back(v);
e[v].push_back(u);
}
} int pre[maxn], inq[maxn], dis[maxn];
void bfs(int s, int &rt){
queue<int> q;
M0(inq, n), M0(dis, n), M0(pre, n);
q.push(s), dis[s] = , inq[s] = ;
int u, v;
while (!q.empty()){
u = q.front();
q.pop();
for (int i = ; i < (int)e[u].size(); ++i){
v = e[u][i];
if (!inq[v])
dis[v] = dis[u] + , inq[v] = , q.push(v), pre[v] = u;
}
}
rt = s;
for (int i = ; i <= n; ++i)
if (dis[rt] < dis[i]) rt = i;
} void bfs(){
queue<int> q;
M0(inq, n), M0(dis, n), M0(from, n);
for (int i = ; i <= m; ++i)
q.push(z[i]), inq[z[i]] = , from[z[i]] = i, dis[z[i]] = ;
int u, v;
while (!q.empty()){
u = q.front();
q.pop();
for (int i = ; i < (int)e[u].size(); ++i){
v = e[u][i];
if (!inq[v])
dis[v] = dis[u] + , inq[v] = , q.push(v), from[v] = from[u];
}
}
} int check(const int len, int& x, int &y){
M0(L, n), M0(R, n), M0(cov, n);
int d;
int mleft = m + , mright = ;
for (int i = ; i <= n; ++i){
d = len - dis[i];
if (d < ) return ;
L[i] = max(, from[i] - d);
R[i] = min(m, from[i] + d);
mleft = min(mleft, R[i]);
mright = max(mright, L[i]);
}
for (int i = ; i <= n; ++i)
if ((L[i] <= mleft && R[i] >= mleft) || (L[i] <= mright && R[i] >= mright)) continue;
else return ;
x = mleft, y = mright;
if (x == y)
(y < m) ? ++y : --x;
return ;
} void solve(){
int s, t;
bfs(, s), bfs(s, t);
m = ;
M0(inz, n), M0(pos, n);
while (t) z[++m] = t, pos[t] = m, t = pre[t];
bfs();
int l = , r = n, mid;
int x, y;
while (l <= r){
mid = (l + r) >> ;
if (check(mid, x, y))
r = mid - , ans = mid, ansx = z[x], ansy = z[y];
else l = mid + ;
}
printf("%d %d %d\n", ans, ansx, ansy);
} int main(){
int cas;
scanf("%d", &cas);
while (cas--){
init();
solve();
}
}

code(o(n)):

 #include <bits/stdc++.h>
#define x first
#define y second
#define M0(a) memset(a, 0, sizeof(int) * (n+10))
#define Inf 0x3fffffff
using namespace std;
const int maxn = ;
vector<int> e[maxn];
pair<int, int> len[maxn][], ans2[maxn][], tmp[], one(, ), zero(, );
int fa[maxn], ans1[maxn], n, ans[maxn], z[maxn];
int ans_x, ans_y, ans_len; int inq[maxn], dis[maxn], pre[maxn];
int pos[maxn], tot;
void bfs(){
M0(inq), M0(fa);
queue<int> q;
q.push(), inq[] = , pos[tot = ] = ;
int u, v;
while (!q.empty()){
u = q.front();
q.pop();
for (int i = ; i < (int)e[u].size(); ++i){
v = e[u][i];
if (!inq[v])
fa[v] = u, q.push(v), inq[v] = , pos[++tot] = v;
}
}
} void gao1(const int& u){
int v;
for (int i = ; i < (int)e[u].size(); ++i){
v = e[u][i];
if (v == fa[u]) continue;
for (int j = ; j < ; ++j) tmp[j] = len[u][j];
tmp[] = make_pair(len[v][].x + , v);
sort(tmp, tmp + , greater<pair<int, int> >());
for (int j = ; j < ; ++j) len[u][j] = tmp[j];
if (ans1[v] > ans2[u][].x){
swap(ans2[u][], ans2[u][]);
ans2[u][] = make_pair(ans1[v], v);
} else if (ans1[v] > ans2[u][].x)
ans2[u][] = make_pair(ans1[v], v);
ans1[u] = max(ans1[u], ans1[v]);
}
ans1[u] = max(ans1[u], len[u][].x + len[u][].x - );
} int ff, s[];
int ss[maxn], max_d[maxn];
void gao2(const int &u){
ff = fa[u];
ss[u] = ss[ff];
if (len[ff][].y == u)
s[] = len[ff][].x, s[] = len[ff][].x;
else if (len[ff][].y == u)
s[] = len[ff][].x, s[] = len[ff][].x;
else
s[] = len[ff][].x, s[] = len[ff][].x;
s[] = max_d[ff];
sort(s, s + , greater<int>() );
ss[u] = max(s[] + s[] - , ss[u]);
max_d[u] = s[] + ;
if (ans2[ff][].y == u)
ss[u] = max(ss[u], ans2[ff][].x);
else
ss[u] = max(ss[u], ans2[ff][].x);
ans[u] = max(ss[u], ans1[u]);
} void pre_do(){
M0(ss), M0(max_d);
for (int i = ; i <= n; ++i){
len[i][] = len[i][] = len[i][] = one;
ans2[i][] = ans2[i][] = zero;
}
} void init(){
scanf("%d", &n);
pre_do();
for (int i = ; i <= n; ++i)
e[i].clear();
int u, v;
for (int i = ; i < n; ++i){
scanf("%d%d", &u, &v);
e[u].push_back(v);
e[v].push_back(u);
}
} void bfs(int s, int &t, const int& other){
queue<int> q;
M0(inq), M0(pre);
memset(dis, -, sizeof(int) * (n+));
q.push(s), dis[s] = , inq[s] = ;
int u, v;
while (!q.empty()){
u = q.front();
q.pop();
for (int i = ; i < (int)e[u].size(); ++i){
v = e[u][i];
if (v == other) continue;
if (!inq[v])
dis[v] = dis[u] + , inq[v] = , q.push(v), pre[v] = u;
}
}
t = s;
for (int i = ; i <= n; ++i)
if (dis[t] < dis[i]) t = i;
} void solve(){
M0(fa), M0(ans1);
bfs();
for (int i = n; i >= ; --i)
gao1(pos[i]);
for (int i = ; i <= n; ++i)
gao2(pos[i]);
int rt = ;
for (int i = ; i <= n; ++i)
if (ans[rt] > ans[i]) rt = i;
// cout << rt << endl;
ans_len = ans[rt] / ;
int x, y;
bfs(rt, x, fa[rt]);
bfs(x, y, fa[rt]);
int m = ;
while (y) z[m++] = y, y = pre[y];
ans_x = z[m/];
bfs(fa[rt], x, rt);
bfs(x, y, rt);
m = ;
while (y) z[m++] = y, y = pre[y];
ans_y = z[m/];
printf("%d %d %d\n",ans_len, ans_x, ans_y); } int main(){
int cas;
scanf("%d", &cas);
while (cas--){
init();
solve();
}
}

zoj3820的更多相关文章

  1. ZOJ-3820 Building Fire Stations 题解

    题目大意: 一棵树,在其中找两个点,使得其他点到这两个的距离的较小值的最大值的最小值及其方案. 思路: 首先显然一棵树的直径的中点到其他点的距离的最大值必定比其他点的小. 那么感性思考一下就将一棵树的 ...

  2. zoj3820 Building Fire Stations 树的中心

    题意:n个点的树,给出n-1条边,每条边长都是1,两个点建立防火站,使得其他点到防火站的最远距离最短. 思路:比赛的时候和队友一开始想是把这两个点拎起来,使得层数最少,有点像是树的中心,于是就猜测是将 ...

  3. 求树的直径和中心(ZOJ3820)

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5374 Building Fire Stations Time Limit: 5 ...

  4. zoj3820 树的直径+二分

    这题是个遗憾 !!!!!当时一直不敢相信两个站一定在直径上,赛后想想自己真的是脑袋抽风, 如果其中一个站不在直径上就反向的说明了这条不是直径.可以很明白我们可以肯定的是有一个点一定在直径上假如另外一个 ...

随机推荐

  1. 探索未知种族之osg类生物---器官初始化二

    那我们回到ViewerBase::frame函数中来,继续看看为什么osg生命刚刚出生的时候会大哭,除了初始化了eventQuene和cameraManipulator之外还对那些器官进行了初始化.在 ...

  2. Ubuntu下安装VS code

    sudo add-apt-repository ppa:ubuntu-desktop/ubuntu-make sudo apt-get update sudo apt-get install ubun ...

  3. samtools

    samtools 用法 samtools <command> [options] command 见以下列表, 每个 command 的 options 也不同 dict faidx in ...

  4. [Hbase]Hbase容灾方案

    介绍两种HBase的数据备份或者容灾方案:Snapshot,Replication: 一.Snapshot 开启快照功能,在hbase-site.xml文件中添加如下配置项: <property ...

  5. 【UI测试】--多窗口&系统资源

  6. STL基础2:vector中使用结构体

    #include <iostream> #include <vector> #include <numeric> #include <algorithm> ...

  7. rpm安装jdk7

    原文:http://www.centoscn.com/image-text/config/2015/0208/4658.html 系统环境:centos-6.5 安装方式:rpm安装 软件:jdk-7 ...

  8. 比较完整的HIS系统解释(转载记录)

    HIS系统即医院信息系统(全称为Hospital Information System).在国际学术界,它已被公认为是新兴的医学信息学的重要分支.HIS系统的有效运行,将提高医院各项工作的效率和质量, ...

  9. PL/SQL Developer 导出csv文件,用excel打开中文显示乱码

      用PL/SQL Developer的导出csv功能把sql语句的查询结果导出到一个csv文件.这个sql查询的结果里面有中文,最后用execel打开的时候发现中文全部是乱码. 方法 1 导出csv ...

  10. Servlet------EL表达式

    EL表达式是: Expression Language.一种写法非常简介的表达式.语法简单易懂,便于使用..获取作用域的数据.... 对比: 传统方式获取作用域数据:                缺 ...