题意

基环树上找到一个点(可以在边上)使得它到树上最远点的距离最小,输出最小距离

题解

如果是一棵树,答案就是树的直径\(/2\)

如果是基环树,那么很好证明删去环上的某一条边是不影响答案的。于是断环为链,单调队列维护\(dep+sum,dep-sum\)的最大值和次大值,然后算直径,如果两个最大值是同个结点就取一个次大,否则都取最大。

#include <algorithm>
#include <cstdio>
using namespace std; typedef long long ll; const int N = 1e5 + 10; struct Edge {
int v, w, nxt;
} e[N << 1];
int hd[N], p;
void link(int u, int v, int w) {
e[p] = (Edge) {v, w, hd[u]};
hd[u] = p ++;
} int n, dfn[N], idx;
int fa[N], fw[N], c[N], d[N], cnt;
bool cir[N]; void dfs(int u, int cur = -1) {
dfn[u] = ++ idx;
for(int i = hd[u]; ~ i; i = e[i].nxt) if(i != cur) {
int v = e[i].v, w = e[i].w;
if(!dfn[v]) {
fa[v] = u; fw[v] = w; dfs(v, i ^ 1);
} else if(dfn[v] < dfn[u]) {
cnt ++; cir[c[cnt] = u] = 1; d[cnt] = w;
for(int j = u; j != v; j = fa[j]) {
cnt ++; cir[c[cnt] = fa[j]] = 1; d[cnt] = fw[j];
}
}
}
} ll mdep[N][2], tree_d; void dfs2(int u, int f = -1) {
for(int i = hd[u]; ~ i; i = e[i].nxt) {
int v = e[i].v;
if(v == f || cir[v]) continue ;
dfs2(v, u);
ll dis = e[i].w + mdep[v][0];
if(dis > mdep[u][0]) {
mdep[u][1] = mdep[u][0];
mdep[u][0] = dis;
} else if(dis > mdep[u][1]) {
mdep[u][1] = dis;
}
}
tree_d = max(tree_d, mdep[u][0] + mdep[u][1]);
} int main() {
scanf("%d", &n);
fill(hd + 1, hd + n + 1, -1);
for(int u, v, w, i = 1; i <= n; i ++) {
scanf("%d%d%d", &u, &v, &w);
link(u, v, w); link(v, u, w);
}
dfs(1);
static ll dep[N << 1], sum[N << 1], ans = 1ll << 62;
for(int i = 1; i <= cnt; i ++) {
dfs2(c[i]);
dep[i] = dep[i + cnt] = mdep[c[i]][0];
}
for(int i = 1; i <= cnt << 1; i ++)
sum[i] = sum[i - 1] + d[i > cnt ? i - cnt : i]; static int q1[N << 1], l1, r1;
static int q2[N << 1], l2, r2;
#define val1(u) dep[u] - sum[u]
#define val2(u) dep[u] + sum[u]
for(int i = 1; i <= cnt << 1; i ++) {
for(; l1 < r1 && q1[l1] + cnt - 1 < i; l1 ++) ;
for(; r1 - l1 > 1 && q1[l1 + 1] + cnt - 1 < i; l1 ++) q1[l1 + 1] = q1[l1];
for(; l2 < r2 && q2[l2] + cnt - 1 < i; l2 ++) ;
for(; r2 - l2 > 1 && q2[l2 + 1] + cnt - 1 < i; l2 ++) q2[l2 + 1] = q2[l2]; for(; r1 - l1 > 2 && val1(q1[r1 - 1]) <= val1(i); r1 --) ;
q1[r1 ++] = i;
if(r1 - l1 <= 3) {
for(int j = r1 - 1; j > l1; j --)
if(val1(q1[j]) > val1(q1[j - 1])) swap(q1[j], q1[j - 1]);
}
for(; r2 - l2 > 2 && val2(q2[r2 - 1]) <= val2(i); r2 --) ;
q2[r2 ++] = i;
if(r2 - l2 <= 3) {
for(int j = r2 - 1; j > l2; j --)
if(val2(q2[j]) > val2(q2[j - 1])) swap(q2[j], q2[j - 1]);
}
if(i >= cnt && r1 - l1 > 1) {
int a1 = q1[l1], a2 = q1[l1 + 1];
int b1 = q2[l2], b2 = q2[l2 + 1];
ll cir_d = 0;
if(a1 == b1) cir_d = max(val1(a1) + val2(b2), val1(a2) + val2(b1));
else cir_d = val1(a1) + val2(b1);
ans = min(ans, max(tree_d, cir_d));
}
}
printf("%lld.%c\n", ans >> 1, ans & 1 ? '5' : '0');
return 0;
}

\(\text{Codeforces 835F}\)是一样的题,数据范围乘\(2\),改一下输出就行.

什么,\(\text{Wrong Answer}\)?

我觉得这是一个错误的解法,回头有时间更新一种用前后缀的做法。

如果我几个月都没更 可以在评论里捶我

「BZOJ 3242」「NOI 2013」快餐店「基环树」的更多相关文章

  1. 「BZOJ 1791」「IOI 2008」Island「基环树」

    题意 求基环树森林所有基环树的直径之和 题解 考虑的一个基环树的直径,只会有两种情况,第一种是某个环上结点子树的直径,第二种是从两个环上结点子树内的最深路径,加上环上这两个结点之间的较长路径. 那就找 ...

  2. Solution -「基环树」做题记录

    写的大多只是思路,比较简单的细节和证明过程就不放了,有需者自取. 基环树简介 简单说一说基环树吧.由名字扩展可得这是一类以环为基础的树(当然显然它不是树. 通常的表现形式是一棵树再加一条非树边,把图画 ...

  3. 【BZOJ 3242】【UOJ #126】【CodeVS 3047】【NOI 2013】快餐店

    http://www.lydsy.com/JudgeOnline/problem.php?id=3242 http://uoj.ac/problem/126 http://codevs.cn/prob ...

  4. BZOJ - 3242 :快餐店 (基环树DP) 最小化半径

    题意:给定N点N边的无向连通图,现在让你在图中找一点作为餐厅,使得最远点距离这点最近. 思路:为了保留整数,我们求最小直径,最后去除2.  直径来源于两部分: 1,在外向树中: 那么就是树的直接,一棵 ...

  5. bzoj 2878: [Noi2012]迷失游乐园【树上期望dp+基环树】

    参考:https://blog.csdn.net/shiyukun1998/article/details/44684947 先看对于树的情况 设d[u]为点u向儿子走的期望长度和,du[u]为u点的 ...

  6. 「BZOJ 4228」Tibbar的后花园

    「BZOJ 4228」Tibbar的后花园 Please contact lydsy2012@163.com! 警告 解题思路 可以证明最终的图中所有点的度数都 \(< 3\) ,且不存在环长是 ...

  7. 「BZOJ 3645」小朋友与二叉树

    「BZOJ 3645」小朋友与二叉树 解题思路 令 \(G(x)\) 为关于可选大小集合的生成函数,即 \[ G(x)=\sum[i\in c ] x^i \] 令 \(F(x)\) 第 \(n\) ...

  8. 「BZOJ 4502」串

    「BZOJ 4502」串 题目描述 兔子们在玩字符串的游戏.首先,它们拿出了一个字符串集合 \(S\),然后它们定义一个字符串为"好"的,当且仅当它可以被分成非空的两段,其中每一段 ...

  9. 「BZOJ 4289」 PA2012 Tax

    「BZOJ 4289」 PA2012 Tax 题目描述 给出一个 \(N\) 个点 \(M\) 条边的无向图,经过一个点的代价是进入和离开这个点的两条边的边权的较大值,求从起点 \(1\) 到点 \( ...

随机推荐

  1. Python numpy函数:reshape()

    reshape()函数用于改变数组对象的形状: import numpy as np a = np.array([1,2,3,4,5,6,7,8]) #转换成2D数组 b = a.reshape((2 ...

  2. Pager分页

    分页组件: /// <summary> /// 分页组件 /// </summary> public class PagerHelper { /// <summary&g ...

  3. 讯为开发板的最小LINUX系统烧写及U盘的挂载及卸载

    fdisk -c 0 fatformat mmc 0:1ext3format mmc 0:2ext3format mmc 0:3ext3format mmc 0:4 fastboot fastboot ...

  4. spring容器启动的三种方式

    一.在Web项目中,启动Spring容器的方式有三种,ContextLoaderListener.ContextLoadServlet.ContextLoaderPlugin. 1.1.监听器方式: ...

  5. HAproxy+Mycat

    haproxy+mycat搭建haproxy server 10.0.1.134mycat server 10.0.1.134,10.0.1.135mysql master 10.0.1.134mys ...

  6. Idea编译器 报@Override错误

    据说这是jdk的问题,@Override是JDK5就已经有了,但有个小小的Bug,就是不支持对接口的实现,认为这不是Override 而JDK6修正了这个Bug,无论是对父类的方法覆盖还是对接口的实现 ...

  7. iOS类目、延展和协议

    类目:为已知的类增加新的方法:注意:类目里面只能写方法,不能写声明和属性,所以,类目不能作为接口来用 1.类目无法向已有类中添加实例变量.2.如果类目中的方法和已有类中的方法名称冲突时,类目中的方法优 ...

  8. paramiko连接方式

    链接方法: 方式一: ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh. ...

  9. oracle——pl/sql 查询中文乱码

    1.查看服务器端编码select userenv('language') from dual;我实际查到的结果为:AMERICAN_AMERICA.AL32UTF82.执行语句 select * fr ...

  10. mysql如何开启远程连接(默认未开启,即使密码正确,仍然无法访问)

    mysql如何开启远程连接 | 浏览:1846 | 更新:2015-03-11 20:19 1 2 3 4 5 6 分步阅读 百度经验:jingyan.baidu.com 大家在公司工作中,经常会遇到 ...