「BZOJ 3242」「NOI 2013」快餐店「基环树」
题意
基环树上找到一个点(可以在边上)使得它到树上最远点的距离最小,输出最小距离
题解
如果是一棵树,答案就是树的直径\(/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」快餐店「基环树」的更多相关文章
- 「BZOJ 1791」「IOI 2008」Island「基环树」
题意 求基环树森林所有基环树的直径之和 题解 考虑的一个基环树的直径,只会有两种情况,第一种是某个环上结点子树的直径,第二种是从两个环上结点子树内的最深路径,加上环上这两个结点之间的较长路径. 那就找 ...
- Solution -「基环树」做题记录
写的大多只是思路,比较简单的细节和证明过程就不放了,有需者自取. 基环树简介 简单说一说基环树吧.由名字扩展可得这是一类以环为基础的树(当然显然它不是树. 通常的表现形式是一棵树再加一条非树边,把图画 ...
- 【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 ...
- BZOJ - 3242 :快餐店 (基环树DP) 最小化半径
题意:给定N点N边的无向连通图,现在让你在图中找一点作为餐厅,使得最远点距离这点最近. 思路:为了保留整数,我们求最小直径,最后去除2. 直径来源于两部分: 1,在外向树中: 那么就是树的直接,一棵 ...
- bzoj 2878: [Noi2012]迷失游乐园【树上期望dp+基环树】
参考:https://blog.csdn.net/shiyukun1998/article/details/44684947 先看对于树的情况 设d[u]为点u向儿子走的期望长度和,du[u]为u点的 ...
- 「BZOJ 4228」Tibbar的后花园
「BZOJ 4228」Tibbar的后花园 Please contact lydsy2012@163.com! 警告 解题思路 可以证明最终的图中所有点的度数都 \(< 3\) ,且不存在环长是 ...
- 「BZOJ 3645」小朋友与二叉树
「BZOJ 3645」小朋友与二叉树 解题思路 令 \(G(x)\) 为关于可选大小集合的生成函数,即 \[ G(x)=\sum[i\in c ] x^i \] 令 \(F(x)\) 第 \(n\) ...
- 「BZOJ 4502」串
「BZOJ 4502」串 题目描述 兔子们在玩字符串的游戏.首先,它们拿出了一个字符串集合 \(S\),然后它们定义一个字符串为"好"的,当且仅当它可以被分成非空的两段,其中每一段 ...
- 「BZOJ 4289」 PA2012 Tax
「BZOJ 4289」 PA2012 Tax 题目描述 给出一个 \(N\) 个点 \(M\) 条边的无向图,经过一个点的代价是进入和离开这个点的两条边的边权的较大值,求从起点 \(1\) 到点 \( ...
随机推荐
- 在CentOS上安装PowerShell
微软刚刚开源了PowerShell,目前在Linux和MacOS上都能安装.具体的链接如下: https://github.com/PowerShell/PowerShell 本文将介绍如何在Cent ...
- java继承初级
总结:重写方法,方法体内容不同. 还有子类都不能加public.它表示公共,一个程序只能有一个公共类 package com.sa; public class Ac { public void rea ...
- PAT L3-008. 喊山(BFS)C4 初赛30分
喊山(30 分) 喊山,是人双手围在嘴边成喇叭状,对着远方高山发出“喂—喂喂—喂喂喂……”的呼唤.呼唤声通过空气的传递,回荡于深谷之间,传送到人们耳中,发出约定俗成的“讯号”,达到声讯传递交流的目的. ...
- python的raw_input()函数。 函数的可变对象和不可变对象作为参数传递。
python的raw_input()函数, 接受键盘输入, 其返回值是字符串类型, 所以当输入的是数字时, 如果是想参与算术运算, 必须要对其进行类型转换. python的参数传递, 对于可变对象和不 ...
- 重新认识synchronized(下)
synchronized既保证原子性,又保证内存可见性,是一种线程同步的方式,是锁机制的一种java实现.synchronized的实现基于JVM底层,JVM是基于monitor实现的,而monito ...
- 图解缓存淘汰算法三之FIFO
1.概念分析 FIFO(First In First Out),即先进先出.最先进入的数据,最先出来.一个很简单的算法.只要使用队列数据结构即可实现.那么FIFO淘汰算法基于的思想是"最近刚 ...
- python django ORM 性能优化 select_related & prefetch_related
q = models.UserInfo.objects.all() select * from userinfo select * from userinfo inner join usertype ...
- 使用mui框架后a标签无法跳转
由于最近工作项目上使用到前台mui框架,笔者在将H5转换为jsp时,遇见各种各样问题,原因归结为对mui框架不熟悉,今天就遇见一个特别奇怪的问题,界面中超链接<a>标签无法跳转,笔者试着添 ...
- C语言学习笔记--指针概念
指针也是一种变量,占有内存空间,用来保存内存地址,在32位系统中指针的占用的内存大小为4个字节 1.*号的意义 (1)在指针声明时,*号表示所声明的变量为指针 (2)在指针使用时,*号表示取指针所指向 ...
- Java的JAR包, EAR包 ,WAR包 都是干什么的,有什么区别
JAR包:打成JAR包的代码,一般作为工具类,在项目中,会应用到N多JAR工具包: WAR包:JAVA WEB工程,都是打成WAR包,进行发布,如果我们的服务器选择TOMCAT等轻量级服务器,一般就打 ...