题目链接

BZOJ3242

题解

题意很清楚,找一点使得最远点最近

如果是一棵树,就是直径中点

现在套上了一个环,我们把环单独拿出来

先求出环上每个点外向树直径更新答案,并同时求出环上每个点外向的最远距离\(val[i]\)

首先要明白以下事实:

①删掉任意一条边不会使答案更优

②环上存在一条边,使得删掉后答案不变

所以我们要做的就是枚举这条边,然后快速求出断掉后的直径

如何快速求出一棵树的直径?

我们同样在剩余的环上找一个断边,直径只有两种情况:

①在断边的任意一侧

②经过断边

情况①,我们只需令\(g[i]\)表示从断边一端\(x\)到\(i\)所形成的树的直径

\[g[i] = max\{g[i - 1],val[i] + dis(i,x)\}
\]

这个可以用单调队列优化

情况②,令\(f[i]\)表示断边一端\(u\)到\(i\)中\(val[i]\)的最大值

就可以直接求出了

然后问题就解决了

复杂度是\(O(n)\)的

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define mp(a,b) make_pair<int,int>(a,b)
#define cls(s) memset(s,0,sizeof(s))
#define cp pair<int,int>
#define LL long long int
using namespace std;
const int maxn = 100005,maxm = 100005;
const LL INF = 10000000000000000ll;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
return out * flag;
}
int h[maxn],ne = 1;
struct EDGE{int to,nxt,f; LL w;}ed[maxn << 1];
inline void build(int u,int v,LL w){
ed[++ne] = (EDGE){v,h[u],1,w}; h[u] = ne;
ed[++ne] = (EDGE){u,h[v],1,w}; h[v] = ne;
}
int n,c[maxn],ci,incir[maxn],fa[maxn];
LL Lcir,sum[maxn],dep[maxn],Len[maxn],F[maxn];
void dfs(int u){
Redge(u) if ((to = ed[k].to) != fa[u]){
if (!dep[to]){
dep[to] = dep[u] + ed[k].w; fa[to] = u;
dfs(to);
}
else if (dep[to] < dep[u]){
ed[k].f = ed[k ^ 1].f = 0;
Lcir = dep[u] - dep[to] + ed[k].w;
for (int i = u; i != to; i = fa[i]){
c[++ci] = i;
sum[ci] = dep[i] - dep[fa[i]];
}
c[++ci] = to;
for (int i = ci; i; i--)
sum[i] = sum[i - 1];
for (int i = 1; i <= ci; i++)
sum[i] += sum[i - 1];
}
}
}
LL d[maxn];
int rt;
void DFS(int u,int flag){
if (d[u] > d[rt]) rt = u;
Redge(u) if (!incir[to = ed[k].to] && to != fa[u]){
fa[to] = u; d[to] = d[u] + ed[k].w;
DFS(to,flag);
if (flag) F[u] = max(F[u],F[to] + ed[k].w);
}
}
void dfs1(int u){
if (d[u] > d[rt]) rt = u;
Redge(u) if (ed[k].f && (to = ed[k].to) != fa[u]){
fa[to] = u; d[to] = d[u] + ed[k].w;
dfs1(to);
}
}
LL ans,f1[maxn],f2[maxn],g1[maxn],g2[maxn];
LL S[maxn],val[maxn],qv[maxn << 1];
int head,tail;
void work(){
for (int i = 1; i <= ci; i++){
S[i] = sum[i]; val[i] = F[c[i]];
}
for (int i = 1; i <= ci; i++){
f1[i] = max(f1[i - 1],val[i] + S[i]);
}
qv[head = tail = 0] = val[1] - S[1];
g1[1] = val[1];
for (int i = 2; i <= ci; i++){
g1[i] = max(g1[i - 1],val[i] + S[i] + qv[head]);
while (head <= tail && val[i] - S[i] >= qv[tail]) tail--;
qv[++tail] = val[i] - S[i];
}
for (int i = ci; i; i--){
f2[i] = max(f2[i + 1],val[i] + S[ci] - S[i]);
}
qv[head = tail = 0] = val[ci] + S[ci];
g2[ci] = val[ci];
for (int i = ci - 1; i; i--){
g2[i] = max(g2[i + 1],val[i] - S[i] + qv[head]);
while (head <= tail && val[i] + S[i] >= qv[tail]) tail--;
qv[++tail] = val[i] + S[i];
}
LL ret = INF,len = Lcir - S[ci];
for (int i = 1; i < ci; i++)
ret = min(ret,max(f1[i] + f2[i + 1] + len,max(g1[i],g2[i + 1])));
rt = 1; d[rt] = fa[rt] = 0;
dfs1(rt);
d[rt] = 0; fa[rt] = 0;
dfs1(rt);
ret = min(ret,d[rt]);
ans = max(ans,ret);
//REP(i,ci) printf("%d f1[] = %lld f2 = %lld g1 = %lld g2 = %lld\n",i,f1[i],f2[i],g1[i],g2[i]);
}
int main(){
n = read(); int a,b,w;
REP(i,n) a = read(),b = read(),w = read(),build(a,b,w);
dep[1] = 1; dfs(1);
REP(i,ci) incir[c[i]] = true;
REP(i,ci){
int u = c[i]; incir[u] = false;
rt = u ; d[u] = fa[u] = 0;
DFS(u,1);
d[rt] = 0; fa[rt] = 0;
DFS(rt,0);
Len[u] = d[rt];
ans = max(ans,Len[u]);
incir[u] = true;
}
work();
printf("%.1lf\n",ans / 2.0);
return 0;
}

BZOJ3242 [Noi2013]快餐店 【环套树 + 单调队列dp】的更多相关文章

  1. BZOJ 1791 岛屿(环套树+单调队列DP)

    题目实际上是求环套树森林中每个环套树的直径. 对于环套树的直径,可以先找到这个环套树上面的环.然后把环上的每一点都到达的外向树上的最远距离作为这个点的权值. 那么直径一定就是从环上的某个点开始,某个点 ...

  2. 【BZOJ-2892&1171】强袭作战&大sz的游戏 权值线段树+单调队列+标记永久化+DP

    2892: 强袭作战 Time Limit: 50 Sec  Memory Limit: 512 MBSubmit: 45  Solved: 30[Submit][Status][Discuss] D ...

  3. bzoj 1791: [Ioi2008]Island 岛屿【基环树+单调队列优化dp】

    我太菜了居然调了一上午-- 这个题就是要求基环树森林的基环树直径和 大概步骤就是找环->dp找每个环点最远能到达距离作为点权->复制一倍环,单调队列dp 找环是可以拓扑的,但是利用性质有更 ...

  4. 1304F2 - Animal Observation (hard version) 线段树or单调队列 +DP

    1304F2 - Animal Observation (hard version) 线段树or单调队列 +DP 题意 用摄像机观察动物,有两个摄像机,一个可以放在奇数天,一个可以放在偶数天.摄像机在 ...

  5. CF480E Parking Lot(单调队列+dp然鹅并不是优化)

    (全英文题面所以直接放化简题意) 题意:在一个二维平面内,初始有一些点,然后每个时间点加入一些点,对每个时间点求平面内最大的无障碍正方形 (这次的题目是真的神仙啊...) 首先,考虑暴力,如果对每一个 ...

  6. POJ 3017 单调队列dp

    Cut the Sequence Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 8764   Accepted: 2576 ...

  7. BZOJ 1012 线段树||单调队列

    非常裸的线段树  || 单调队列: 假设一个节点在队列中既没有时间优势(早点入队)也没有值优势(值更大),那么显然不管在如何的情况下都不会被选为最大值. 既然它仅仅在末尾选.那么自然能够满足以上的条件 ...

  8. [TyvjP1313] [NOIP2010初赛]烽火传递(单调队列 + DP)

    传送门 就是个单调队列+DP嘛. ——代码 #include <cstdio> ; , t = , ans = ~( << ); int q[MAXN], a[MAXN], f ...

  9. zstu 4237 马里奥的求救——(单调队列DP)

    题目链接:http://oj.acm.zstu.edu.cn/JudgeOnline/problem.php?id=4237 这题可以转化为每次可以走g~d+x步,求最大分数,且最大分数的步数最少. ...

随机推荐

  1. spring-运行时值注入

    在项目中经常使用连接数据库的配置,如下所示 <bean id="dataSource" class="org.apache.commons.dbcp.BasicDa ...

  2. 继上一篇bootstrap框架(首页)弄的资讯页面

    还是和上一篇首页一样给出每一步的注解: 做的有点简单,但是,以后还是会加深的.毕竟是初学者嘛! <html lang="zh-cn">   <head>   ...

  3. Python的Bottle框架中实现最基本的get和post的方法的教程

    这篇文章主要介绍了Python的Bottle框架中实现最基本的get和post的方法的教程,Bottle框架在Python开发者中的人气很高,需要的朋友可以参考下 1.GET方式: # -*- cod ...

  4. R语言学习笔记(十三):零碎知识点(36-40)

    36--diag() 如果它的参数是一个矩阵,它返回的是一个向量 如果它的参数是一个向量,它返回的是一个向量 如果它的参数是一个标量,它返回的是指定大小的单位矩阵 > diag(2) [,1] ...

  5. R语言学习笔记(十二):零碎知识点(31-35)

    31--round(),floor()和ceiling() round()四舍五入取整 floor()向下取整 ceiling()向上取整 > round(3.5) [1] 4 > flo ...

  6. 贪心算法之Huffman

    Huffman编码,权重越大,离根节点越大.所以就是不断的选取两个最小的树,然后组成一颗新树,加入集合,然后去除已选的两棵树.不断的循环,直到最后的树的集合只剩下一棵,则构建完成,最后输出Huffma ...

  7. python2中将Unicode编码的中文和str相互转换

    在python2x版本中 关于中文汉字转换 1.中文------字符串格式 >>> s = '汉字' >>> type(s) <type 'str'> ...

  8. java 堆栈内存分析详解

    计算机术语里面堆和栈代表不同的存储结构:stack-栈:heap-堆 所以java虚拟机(JVM)中堆和栈是两种内存 堆.栈对比 对比点 堆 栈 JVM中的功能 内存数据区 内存指令区 动静态 运行时 ...

  9. C#中Equals和= =(等于号)的比较)(转载)

    C#中Equals和= =(等于号)的比较) 相信很多人都搞不清Equals和 = =的区别,只是零星的懂一点,现在就让我带大家来进行一些剖析 一.           值类型的比较 对于值类型来说  ...

  10. P1823 音乐会的等待(单调栈)

    P1823 音乐会的等待 题目描述 N个人正在排队进入一个音乐会.人们等得很无聊,于是他们开始转来转去,想在队伍里寻找自己的熟人.队列中任意两个人A和B,如果他们是相邻或他们之间没有人比A或B高,那么 ...