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

解:很容易想到找出直径然后/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. 【学亮IT手记】mysql创建/查看/切换数据库

    --创建数据库 create database web_test1 CHARACTER set utf8; --切换数据库 use web_test1; --查看当前使用的数据库 select DAT ...

  2. 如何在TypeScript中使用第三方JavaScript框架

    一.安装typings 使用npm全局安装typings :npm install -g typings 安装成功. 二,搜索资源,支持模糊搜索:typings search base64 三.安装t ...

  3. 记录SSM框架项目迁移SpringBoot框架-----pom.xml的迁移

    第一步:迁移pom.xml文件(去除spring相关的依赖) SSM中的pom: <project xmlns="http://maven.apache.org/POM/4.0.0&q ...

  4. SpringMVC配置三大组件

    1.组件扫描器 使用组件扫描器省去在spring容器配置每个Controller类的繁琐. 使用<context:component-scan>自动扫描标记@Controller的控制器类 ...

  5. nfs+keepalived高可用

    1台nfs主被服务器都下载nfs.keepalived yum install nfs-utils rpcbind keepalived -y 2台nfs服务器nfs挂载目录及配置必须相同 3.在主n ...

  6. @EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})

    @EnableAutoConfiguration 作用:Spring Boot会自动根据你jar包的依赖来自动配置项目. 例如当你项目下面有HSQLDB的依赖时,Spring Boot会创建默认的内存 ...

  7. 996.ICU

    996.ICU https://github.com/996icu/996.ICU https://www.zhihu.com/question/317722302 LICENSE https://g ...

  8. 莫烦keras学习自修第一天【keras的安装】

    1. 安装步骤 (1)确保已经安装了python2或者python3 (2)安装numpy,python2使用pip2 install numpy, python3则使用pip3 install nu ...

  9. LOADING Redis is loading the dataset in memory Redis javaAPI实例

    今天在实现Redis客户端API操作Jedis的八种调用方式详解中,遇到了LOADING Redis is loading the dataset in memory错误,经过多番查找资料,找到了解决 ...

  10. Lodop中特殊符号¥打印设计和预览不同

    Lodop中¥符号样式改变问题 Lodop中对超文本样式的解析,虽然说是按照调用的本机ie引擎,但是调用的ie版本可能不同,导致在ie下是一种样式,预览又是另一种样式.可能是有些样式没有具体设置,走的 ...