题意

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

题解

如果是一棵树,答案就是树的直径\(/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. POJ2773(容斥原理)

    Happy 2006 Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 11458   Accepted: 4001 Descr ...

  2. (转)AppCan中调用系统浏览器打开网页

    <!DOCTYPE html> <html> <head> <style>body{ background:#fff; font-size:30px;} ...

  3. JDK 8 - java.util.HashSet 实现机制分析

    JDK 8 Class HashSet<E> Doc: public class HashSet<E> extends AbstractSet<E> impleme ...

  4. eclipse中删除tomcat server 导致不能重新创建该server

    定位到:workspace\.metadata\.plugins\org.eclipse.core.runtime\.settings 1 打开org.eclipse.jst.server.tomca ...

  5. Git学习笔记(三)远程库(GitHub)协同开发,fork和忽略特殊文件

    远程库 远程库,通俗的讲就是不再本地的git仓库!他的工作方式和我们本地的一样,但是要使用他就需要先建立连接! 远程库有两种,一个是自己搭建的git服务器:另一种就是使用GitHub,这个网站就是提供 ...

  6. Java中Return和Finally执行顺序的实现

    下面这段代码的执行结果是怎样的呢? publc int test(){ int x; try{ x = 1; return x; }catch(Exception e){ x = 2; return ...

  7. Hadoop集群 能打开50070端口不能打开8088端口 web浏览器界面

    两天时间,知道现在才把这个东西解决  解决的灵感来源于百度知道一句话谢谢这个哥们 谢谢这个哥们! ​我的目录是在/home/hadoop/tmp  大家如果遇到这个问题,希望能按照我的办法去试一下 2 ...

  8. bootstrap媒体查询常用写法

    @media (max-width: 768px) { /*超小屏幕设备 手机*/ } @media (min-width: 768px) and (max-width: 992px) { /*小屏幕 ...

  9. [codeforces126B]Password

    解题关键:KMP算法中NEXT数组的理解. #include<bits/stdc++.h> #define maxn 1000006 using namespace std; typede ...

  10. SpringBoot07 异常枚举、自定义异常、统一的全局异常处理

    1 异常编号和提示信息统一管理 利用枚举来实现异常的统一管理 package cn.xiangxu.springboottest.enums; import lombok.Getter; /** * ...