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

解:很容易想到找出直径然后/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. day 7-19 Mysql索引原理与查询优化

    一,介绍 1.什么是索引? 一般的应用系统,读写比例在10:1左右,而且插入操作和一般的更新操作很少出现性能问题,在生产环境中,我们遇到最多的,也是最容易出问题的,还是一些复杂的查询操作,因此对查询语 ...

  2. Day 4-11 re正则表达式

    正则表达式就是字符串的匹配规则,在多数编程语言里都有相应的支持,python里对应的模块是re '.' 默认匹配除\n之外的任意一个字符,若指定flag DOTALL,则匹配任意字符,包括换行 '^' ...

  3. jvm相关参数

    官方地址:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jstat.html#BEHHGFAE 一.查看jvm运行参数 1.查看 ...

  4. Error:Failed to resolve: com.android.support:appcompat-v7

    repositories { maven { url "https://maven.google.com" } } implementation 'com.android.supp ...

  5. mysql语句-DML语句

    DML语句 DML是指对数据库中表记录的操作,主要包括数据的增删改查以及更新,下面依次介绍 首先创建一张表:: 表名:emp 字段:ename varchar(20),hiredate date ,s ...

  6. maven + bat 实现快速编译打包模块代码

    pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="htt ...

  7. python之旅第八篇--异常

    判断类与对象关系 isinstance #判断对象obj是否是由cls类创建的 class Foo(object): pass obj = Foo() print isinstance(obj,Foo ...

  8. BZOJ3144[Hnoi2013]切糕——最小割

    题目描述 输入 第一行是三个正整数P,Q,R,表示切糕的长P. 宽Q.高R.第二行有一个非负整数D,表示光滑性要求.接下来是R个P行Q列的矩阵,第z个 矩阵的第x行第y列是v(x,y,z) (1≤x≤ ...

  9. Heron and His Triangle HDU - 6222(pell 大数)

    ---恢复内容开始--- Heron and His Triangle Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/2 ...

  10. Ionic开发遇到的坑整理

    1.修改tabs页的图标,关键是 outline 在使用自定义图标的时候,需要修改 /theme/icons.scss 文件,但是如何定义选中前后的分别使用哪个图标呢 定义选中前的状态 .ion-io ...