题意

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

题解

如果是一棵树,答案就是树的直径\(/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. 在CentOS上安装PowerShell

    微软刚刚开源了PowerShell,目前在Linux和MacOS上都能安装.具体的链接如下: https://github.com/PowerShell/PowerShell 本文将介绍如何在Cent ...

  2. java继承初级

    总结:重写方法,方法体内容不同. 还有子类都不能加public.它表示公共,一个程序只能有一个公共类 package com.sa; public class Ac { public void rea ...

  3. PAT L3-008. 喊山(BFS)C4 初赛30分

    喊山(30 分) 喊山,是人双手围在嘴边成喇叭状,对着远方高山发出“喂—喂喂—喂喂喂……”的呼唤.呼唤声通过空气的传递,回荡于深谷之间,传送到人们耳中,发出约定俗成的“讯号”,达到声讯传递交流的目的. ...

  4. python的raw_input()函数。 函数的可变对象和不可变对象作为参数传递。

    python的raw_input()函数, 接受键盘输入, 其返回值是字符串类型, 所以当输入的是数字时, 如果是想参与算术运算, 必须要对其进行类型转换. python的参数传递, 对于可变对象和不 ...

  5. 重新认识synchronized(下)

    synchronized既保证原子性,又保证内存可见性,是一种线程同步的方式,是锁机制的一种java实现.synchronized的实现基于JVM底层,JVM是基于monitor实现的,而monito ...

  6. 图解缓存淘汰算法三之FIFO

    1.概念分析 FIFO(First In First Out),即先进先出.最先进入的数据,最先出来.一个很简单的算法.只要使用队列数据结构即可实现.那么FIFO淘汰算法基于的思想是"最近刚 ...

  7. python django ORM 性能优化 select_related & prefetch_related

    q = models.UserInfo.objects.all() select * from userinfo select * from userinfo inner join usertype ...

  8. 使用mui框架后a标签无法跳转

    由于最近工作项目上使用到前台mui框架,笔者在将H5转换为jsp时,遇见各种各样问题,原因归结为对mui框架不熟悉,今天就遇见一个特别奇怪的问题,界面中超链接<a>标签无法跳转,笔者试着添 ...

  9. C语言学习笔记--指针概念

    指针也是一种变量,占有内存空间,用来保存内存地址,在32位系统中指针的占用的内存大小为4个字节 1.*号的意义 (1)在指针声明时,*号表示所声明的变量为指针 (2)在指针使用时,*号表示取指针所指向 ...

  10. Java的JAR包, EAR包 ,WAR包 都是干什么的,有什么区别

    JAR包:打成JAR包的代码,一般作为工具类,在项目中,会应用到N多JAR工具包: WAR包:JAVA WEB工程,都是打成WAR包,进行发布,如果我们的服务器选择TOMCAT等轻量级服务器,一般就打 ...