题意:在基环树上找一点,使得这个点到所有点的距离最大值最小。这个点可以在某条边上。

解:很容易想到找出直径然后/2对吧...这里的直径是指任意两点间最短距离的最大值。

然而我这个SB冥思苦想了半天之后想到了一个傻逼绝伦的做法:枚举边!

这个点一定在某条边上。

所以知道边的两端点最长延伸多长即可。

如果是子树里的边,很显然下面那个点就是子树内最长链。而上面那个点就是子树外最长链或深度 + 根节点在环上最长延伸距离

如果是环上的边,就是两端点子树最长链或者环上延伸的最长距离

值得注意的是,这两个"环上最长延伸距离"并不是一样的。

因为前者只有一个点在环上,没有别的环上的点跟它竞争。

而后者要跟环上另一个点相互竞争。所以还要分两种情况。

具体实现上,首先找环,然后每个子树做两次树形DP,第二次是二次扫描与换根法。

然后把环的信息提取出来DP,利用单调队列来求最长延伸距离,反正我写了4个......

最后枚举边判定。

反正就是仔细写,耐心Debug...

(为什么别人1k就能A而我要5k啊...)

 #include <cstdio>
#include <algorithm>
#include <stack>
#include <cstring> typedef long long LL;
const int N = ; struct Edge {
int nex, v;
LL len;
}edge[N << ]; int top = ; int e[N], n, cir[N], tc, p[N], head, tail, fr[N], nex[N], pre[N];
std::stack<int> S;
bool vis[N], is_cir[N];
LL d[N], len1[N], len2[N], lenup[N], dis[N], p2[N], sum[N], Long[N], Long_l[N], Long_r[N]; inline void add(int x, int y, LL z) {
top++;
edge[top].v = y;
edge[top].len = z;
edge[top].nex = e[x];
e[x] = top;
return;
} void Df(int x, int f) {
vis[x] = ;
S.push(x);
for(int i = e[x]; i && !vis[]; i = edge[i].nex) {
int y = edge[i].v;
if(y == f) {
continue;
}
if(vis[y]) {
vis[] = ;
while(x != y) {
x = S.top();
S.pop();
is_cir[x] = ;
cir[++tc] = x;
}
return;
}
Df(y, x);
}
if(vis[]) {
return;
}
S.pop();
vis[x] = ;
return;
} void DFS_1(int x, int f, int aim) { // get d len1 len2
if(!fr[x]) {
fr[x] = fr[f];
}
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y == f || is_cir[y]) {
if(cir[aim] == y) {
dis[aim] = edge[i].len;
nex[x] = y;
pre[y] = x;
}
continue;
}
d[y] = d[x] + edge[i].len;
DFS_1(y, x, aim);
if(len1[x] < len1[y] + edge[i].len) {
len2[x] = len1[x];
len1[x] = len1[y] + edge[i].len;
}
else if(len2[x] < len1[y] + edge[i].len) {
len2[x] = len1[y] + edge[i].len;
}
}
return;
} void DFS_2(int x, int f) {
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y == f || is_cir[y]) {
continue;
}
if(len1[y] + edge[i].len == len1[x]) {
lenup[y] = std::max(lenup[x], len2[x]) + edge[i].len;
}
else {
lenup[y] = std::max(lenup[x], len1[x]) + edge[i].len;
}
DFS_2(y, x);
}
return;
} int main() {
int x, y;
LL z, Sum = ;
double ans = ;
scanf("%d", &n);
for(int i = ; i <= n; i++) {
scanf("%d%d%lld", &x, &y, &z);
add(x, y, z);
add(y, x, z);
ans += z;
}
Df(, ); for(int i = ; i <= tc; i++) {
fr[cir[i]] = cir[i];
DFS_1(cir[i], , (i == tc ? : i + ));
DFS_2(cir[i], );
cir[tc + i] = cir[i];
}
for(int i = ; i <= tc; i++) {
Sum += dis[i];
dis[tc + i] = dis[i];
}
for(int i = ; i <= tc * ; i++) {
sum[i] = sum[i - ] + dis[i];
} LL dt = ;
head = ;
tail = ;
for(int i = ; i <= tc * ; i++) {
// DP
while(head <= tail && sum[i] - sum[p[head]] > Sum - (sum[i] - sum[p[head]])) {
head++;
}
dt += dis[i];
if(head <= tail) {
Long[cir[i]] = std::max(Long[cir[i]], p2[head] + dt);
}
while(head <= tail && len1[cir[i]] - dt >= p2[tail]) {
tail--;
}
p[++tail] = i;
p2[tail] = len1[cir[i]] - dt;
}
head = ;
tail = ;
dt = ;
for(int i = tc * ; i >= ; i--) {
while(head <= tail && sum[p[head]] - sum[i] > Sum - (sum[p[head]] - sum[i])) {
head++;
}
dt += dis[i + ];
if(head <= tail) {
Long[cir[i]] = std::max(Long[cir[i]], p2[head] + dt);
}
while(head <= tail && len1[cir[i]] - dt >= p2[tail]) {
tail--;
}
p[++tail] = i;
p2[tail] = len1[cir[i]] - dt;
}
// -------------------------------------------------------------------------------------------------------
head = ;
tail = ;
dt = ;
dis[tc * + ] = dis[];
for(int i = ; i <= tc * ; i++) {
// DP
while(head <= tail && sum[i] - sum[p[head]] > Sum - (sum[i] - sum[p[head]] + dis[i + ])) {
head++;
}
dt += dis[i];
if(head <= tail) {
Long_l[cir[i]] = std::max(Long_l[cir[i]], p2[head] + dt);
}
while(head <= tail && len1[cir[i]] - dt >= p2[tail]) {
tail--;
}
p[++tail] = i;
p2[tail] = len1[cir[i]] - dt;
}
head = ;
tail = ;
dt = ;
for(int i = tc * ; i >= ; i--) {
while(head <= tail && sum[p[head]] - sum[i] > Sum - (sum[p[head]] - sum[i - ])) {
head++;
}
dt += dis[i + ];
if(head <= tail) {
Long_r[cir[i]] = std::max(Long_r[cir[i]], p2[head] + dt);
}
while(head <= tail && len1[cir[i]] - dt >= p2[tail]) {
tail--;
}
p[++tail] = i;
p2[tail] = len1[cir[i]] - dt;
}
//
for(int i = ; i <= top; i += ) {
int x = edge[i].v, y = edge[i ^ ].v;
LL a, b;
if(is_cir[x] && is_cir[y]) {
if(nex[y] == x) {
std::swap(x, y);
}
a = std::max(Long_l[x], len1[x]);
b = std::max(Long_r[y], len1[y]);
}
else {
if(d[x] > d[y]) {
std::swap(x, y);
}
a = len1[y];
b = std::max(lenup[y] - edge[i].len, d[x] + Long[fr[x]]);
}
if(a < b) {
std::swap(a, b);
}
if(a >= edge[i].len + b) {
ans = std::min(ans, (double)a);
}
else {
ans = std::min(ans, (a + b + edge[i].len) / 2.0);
}
} printf("%.1f", ans);
return ;
}

AC代码

洛谷P1399 快餐店的更多相关文章

  1. 洛谷1640 bzoj1854游戏 匈牙利就是又短又快

    bzoj炸了,靠离线版题目做了两道(过过样例什么的还是轻松的)但是交不了,正巧洛谷有个"大牛分站",就转回洛谷做题了 水题先行,一道傻逼匈牙利 其实本来的思路是搜索然后发现写出来类 ...

  2. 洛谷P1352 codevs1380 没有上司的舞会——S.B.S.

    没有上司的舞会  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond       题目描述 Description Ural大学有N个职员,编号为1~N.他们有 ...

  3. 洛谷P1108 低价购买[DP | LIS方案数]

    题目描述 “低价购买”这条建议是在奶牛股票市场取得成功的一半规则.要想被认为是伟大的投资者,你必须遵循以下的问题建议:“低价购买:再低价购买”.每次你购买一支股票,你必须用低于你上次购买它的价格购买它 ...

  4. 洛谷 P2701 [USACO5.3]巨大的牛棚Big Barn Label:二维数组前缀和 你够了 这次我用DP

    题目背景 (USACO 5.3.4) 题目描述 农夫约翰想要在他的正方形农场上建造一座正方形大牛棚.他讨厌在他的农场中砍树,想找一个能够让他在空旷无树的地方修建牛棚的地方.我们假定,他的农场划分成 N ...

  5. 洛谷P1710 地铁涨价

    P1710 地铁涨价 51通过 339提交 题目提供者洛谷OnlineJudge 标签O2优化云端评测2 难度提高+/省选- 提交  讨论  题解 最新讨论 求教:为什么只有40分 数组大小一定要开够 ...

  6. 洛谷P1371 NOI元丹

    P1371 NOI元丹 71通过 394提交 题目提供者洛谷OnlineJudge 标签云端评测 难度普及/提高- 提交  讨论  题解 最新讨论 我觉得不需要讨论O long long 不够 没有取 ...

  7. 洛谷P1538迎春舞会之数字舞蹈

    题目背景 HNSDFZ的同学们为了庆祝春节,准备排练一场舞会. 题目描述 在越来越讲究合作的时代,人们注意的更多的不是个人物的舞姿,而是集体的排列. 为了配合每年的倒计时,同学们决定排出——“数字舞蹈 ...

  8. 洛谷八月月赛Round1凄惨记

    个人背景: 上午9:30放学,然后因为学校举办读书工程跟同学去书城选书,中午回来开始打比赛,下午又回老家,中间抽出一点时间调代码,回家已经8:50了 也许是7月月赛时“连蒙带骗”AK的太幸运然而因同学 ...

  9. 洛谷 P1379 八数码难题 Label:判重&&bfs

    特别声明:紫书上抄来的代码,详见P198 题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给 ...

随机推荐

  1. MySQL 单个表锁死 对查询语句无响应

    这个时候应该怀疑读取都被加锁,应该尝试使用 show processlist 查看每一个正在运行的进程. 可以看到这样一个列表,里面有使用者即用户,正在使用数据库的 host, 使用的 db 目前的 ...

  2. python函数、模块、包

    一.函数 定义函数: def fun_name(para_list): coding def fun_name(para_list): coding return xxx 使用函数,fun_name( ...

  3. Linux中,去掉终端显示的当前目录的绝对路径

    Linux中,去掉终端显示的当前目录的绝对路径 去~/.bashrc中,找到PS1变量的定义,如果没有,手动加上: 可以将显示输出到标题栏上: #export PS1="[e]2;u@H w ...

  4. Java使用RabbitMQ之订阅分发(Topic)

    使用RabbitMQ进行消息发布和订阅,生产者将消息发送给转发器(exchange),转发器根据路由键匹配已绑定的消息队列并转发消息,主题模式支持路由键的通配. 生产者代码: package org. ...

  5. Windows上安装 TensorFlow及简单命令

    1.官网及帮助文档 官网: https://www.tensorflow.org/install/install_windows 中文帮助文档:https://efeiefei.gitbooks.io ...

  6. linux寻找依赖文件

    在linux下编译安装软件有时候会遇到依赖文件找不到的情况,很多时候可以通过 sudo apt install -f 来解决:实在找不到怎么办,还有一个绝招可以用: 安装  apt-file sudo ...

  7. 使用电脑adb给Essential Phone刷机 —(官方篇)

    用ADB给Essential Phone线刷升级 重要:请确保在刷机前已经解锁,关于解锁教程群里有! 准备 原版boot Twrp boot Magisk卡刷包 到官网下载OTA包 准备好Essent ...

  8. react 粗略使用

    1.首先在index.html页面上写好dom,给他一个id让他引用js里的react. 2.index.js里面的代码就是三步走. 第一步:引用react,各种引用依赖. 第二步:创建dom,但它是 ...

  9. eclipse 等号左边代码补全

    1: 2. 3.完成  “ctrl + shift + l” 代码补全成功

  10. 3.docker基础架构

    docker是一个典型的c/s架构产品. dockerd :为客户端提供  RESTFUL API,响应来自客户端的请求, 采用模块化的架构, 通过专门的 Engine 模块来分发管理各 个来自客户端 ...