题目链接:

http://172.16.0.132/senior/#main/show/5905

题目:

oi_juruo热爱一款名叫黑暗之魂的游戏。在这个游戏中玩家要操纵一名有 点生命值的无火的余灰在一张地图中探险。地图中有$n$个篝火(也就是存档点)。在篝火处休息可以将生命值恢复满。每个篝火都会向其他篝火的其中之一连有一条通道(显然,通道是双向的),这些篝火之间都相互可达。也就是说,这是一张$n$个点,$n$条边的无向连通图。每条通道里都有一些怪物,经过oi_juruo的分析,他得到了每条边的怪物会对他造成的伤害值 .为了向oier们表演他高超的游戏技巧,他要从任意一个篝火跑到任意另一个篝火而不在之间的篝火休息,在此期间,他会和他经过的通道中的怪物战斗并损失 的生命值。现在oi_juruo想知道,他的生命值 至少为多少,才能完成任意一条旅途。oi_juruo并不傻,他会走最安全的路。本题时限为3000ms

题目大意:

给出一棵基环树,定义任意两点之间的距离为两点之间的最短路径,最大距离为多少

题解:

分别考虑环上的每一个点

显然我们首先要找到环,考虑用类似拓扑排序的做法,即每次找度数为1的叶子节点不断向上更新,最后环上的点的度数一定为2

$f[x]$表示以$x$为根的子树中的直径,可以在拓扑排序的过程中处理出

我们已知以环上每一个点为根节点的子树的直径,问题转化成了给出一个环,环上的每一个点有一个点权,点与点之间有边权,设$dis[i][j]$为环上两点$i,j$的距离(最短路径),要计算最大的$f[i]+f[j]+dis[i][j]$

由于只能走最短路径,显然$dis[i]][j]$小于等于环的周长$S$的二分之一。我们断环成链,在可行区间范围内维护单调队列。

具体实现是令$a[i]$为节点$i$的点权,$b[i]$为链开头到节点i的路径前缀和,对于每个$i$,答案就是$a[i]+a[j]+b[i]-b[j](b[i]-b[j]<=\frac{S}{2})$取最大值,显然满足决策单调性

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<iostream>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll; const int N=1e6+;
int n,tot;
ll ans;
int head[N],in[N],tmp[N],qq[N];
ll f[N],dis[N],b[N],a[N];
struct EDGE
{
int to,nxt;
ll w;
}edge[N<<];
inline ll read()
{
char ch=getchar();
ll s=,f=;
while (ch<''||ch>'') {if (ch=='-') f=-;ch=getchar();}
while (ch>=''&&ch<='') {s=(s<<)+(s<<)+ch-'';ch=getchar();}
return s*f;
}
void add(int u,int v,ll w)
{
edge[++tot]=(EDGE){v,head[u],w};
head[u]=tot;
}
void topsort()
{
queue<int> q;
for (int i=;i<=n;i++) if (in[i]==) q.push(i);
while (!q.empty())
{
int k=q.front();q.pop();
for (int i=head[k];i;i=edge[i].nxt)
{
int y=edge[i].to;
if (in[y]==) continue;
ans=max(ans,f[k]+f[y]+edge[i].w);
f[y]=max(f[y],f[k]+edge[i].w);
if ((--in[y])==) q.push(y);
}
}
}
void dp(int x)
{
int t=,y=x,pp;
ll len,S=;
do
{
a[++t]=f[y];
tmp[y]=;
for(pp=head[y];pp;pp=edge[pp].nxt)
if(!tmp[edge[pp].to]&&in[edge[pp].to]==)
{
y=edge[pp].to;
b[t+]=b[t]+edge[pp].w;
break;
}
}while(pp); if (t==) return; if (t==)
{
for (int i=head[y];i;i=edge[i].nxt)
{
if (edge[i].to==x) {len=edge[i].w;break;}
}
ans=max(ans,f[x]+f[y]+len);
return;
} for (int i=head[y];i;i=edge[i].nxt)
{
if (edge[i].to==x)
{
S=b[t]+edge[i].w;
b[t+]=b[t]+edge[i].w;
}
}
for (int i=;i<t;i++) a[i+t]=a[i],b[t+i]=b[t+]+b[i];
int l=,r=;
qq[l]=;
for (int i=;i<*t;i++)
{
while (l<=r&&(b[i]-b[qq[l]]>S/||i-qq[l]>=t)) l++;
if (l<=r) ans=max(ans,b[i]-b[qq[l]]+a[qq[l]]+a[i]);
while (l<=r&&a[qq[r]]-b[qq[r]]<=a[i]-b[i]) r--;
qq[++r]=i;
}
}
int main()
{
freopen("darksoul.in","r",stdin);
freopen("darksoul.out","w",stdout);
n=read();
for (int i=,u,v,w;i<=n;i++)
{
u=read();v=read();w=read();
in[u]++;in[v]++;
if (u==v) continue;
add(u,v,w);add(v,u,w);
}
topsort();
for (int i=;i<=n;i++)
{
if (in[i]==)
{
dp(i);
break;
}
}
printf("%lld\n",ans+);
return ;
}

[JZOJ 5905] [NOIP2018模拟10.15] 黑暗之魂(darksoul) 解题报告 (拓扑排序+单调队列+无向图基环树)的更多相关文章

  1. [NOIP2015模拟10.27] 挑竹签 解题报告(拓扑排序)

    Description 挑竹签——小时候的游戏夏夜,早苗和诹访子在月光下玩起了挑竹签这一经典的游戏.挑竹签,就是在桌上摆上一把竹签,每次从最上层挑走一根竹签.如果动了其他的竹签,就要换对手来挑.在所有 ...

  2. [JZOJ 5893] [NOIP2018模拟10.4] 括号序列 解题报告 (Hash+栈+map)

    题目链接: https://jzoj.net/senior/#main/show/5893 题目: 题解: 考虑暴力怎么做,我们枚举左端点,维护一个栈,依次加入元素,与栈顶元素和栈内第二个元素相同时弹 ...

  3. [jzoj 5930] [NOIP2018模拟10.26】山花 解题报告 (质因数分类)

    题目链接: http://172.16.0.132/senior/#contest/show/2538/2 题目: 小S决定从某一个节点$u$开始对其子树中与$u$距离小于$K$的节点代表的花树进行采 ...

  4. [JZOJ 5906] [NOIP2018模拟10.15] 传送门 解题报告(树形DP)

    题目链接: https://jzoj.net/senior/#contest/show/2528/2 题目: 8102年,Normalgod在GLaDOS的帮助下,研制出了传送枪.但GLaDOS想把传 ...

  5. [JZOJ 5885] [NOIP2018模拟9.27] 物理实验 解题报告 (思维)

    题目链接: https://jzoj.net/senior/#main/show/5885 题目: 题解: 把$a$数组按升序排序 我们可以枚举$x$,发现对于任意$x$,最优情况下$y$一定等于$x ...

  6. [JZOJ 5888] [NOIP2018模拟9.29] GCD生成树 解题报告 (最大生成树+公约数)

    题目链接: http://172.16.0.132/senior/#main/show/5888 题目: 题解: 思路是这样的:两个数的最大公约数一定不会比这两个数的任意一个数大.因此我们把权值相等的 ...

  7. [NOIP2018模拟10.15]比赛报告

    闲扯 昨晚又颓到好晚,Yali的降智光环感觉持续至今... 题面好评 T1T3都玩过 逃) T1没看多久就开始写二分+并查集 然后T3看着眼熟想了一个多小时...结果啥都没想出来 赶紧看T2发现还是没 ...

  8. [jzoj 5926] [NOIP2018模拟10.25] naive 的图 解题报告(kruskal重构树+二维数点)

    题目链接: https://jzoj.net/senior/#main/show/5926 题目: 题解: 显然最小的最大路径在最小生成树上(最小生成树=最小瓶颈生成树) 于是我们建出kruskal重 ...

  9. [JZOJ 5912] [NOIP2018模拟10.18] VanUSee 解题报告 (KMP+博弈)

    题目链接: https://jzoj.net/senior/#contest/show/2530/2 题目: 众所周知,cqf童鞋对哲学有着深入的理解和认识,并常常将哲学思想应用在实际生活中,例如锻炼 ...

随机推荐

  1. SOAPUI 安装及破解

    转自:https://blog.csdn.net/henni_719/article/details/79000130 先下载SOAPUI,我这里用的是5.1.2 PRO  版 下载路径:http:/ ...

  2. CentOS7开启网络配置

    虚拟机在安装时可以开启网络 如果没有开启的话 可以通过以下操作 ip  addr 查看是否开启网络 没有开启的话 cd /etc/sysconfig/network-scripts/ 然后 执行 ls ...

  3. BZOJ 3238 后缀数组+单调栈

    单调栈跑两遍求出来 ht[i]为最小值的那段区间 //By SiriusRen #include <cstdio> #include <cstring> #include &l ...

  4. 实现两个jQuery的API(addClass、text)

    目的 给所有的div添加一个叫“red”的class,为方便看到代码的效果,设置如下css,在设置“red”成功时,文本会变红 .red{ color:red; } 将所有的div中的textCont ...

  5. css实战笔记(一):写网页前的reset工作

    reset.css是每个html必备的样式,其中有各种元素属性清零的代码. 为什么要有reset.css 让各个浏览器的CSS样式有一个统一的基准,比如清除各个浏览器为元素自带的margin.padd ...

  6. 一个基于React整套技术栈+Node.js的前端页面制作工具

    pagemaker是一个前端页面制作工具,方便产品,运营和视觉的同学迅速开发简单的前端页面,从而可以解放前端同学的工作量.此项目创意来自网易乐得内部项目nfop中的pagemaker项目.原来项目的前 ...

  7. 七天C#小结

    从基础的理论知识,到最后一天,能够理解并且自己编写出一些经典的事例,自己期初觉得不会这么快,几乎是零基础的自己从什么都不会,到七天后能够独立思考并且编写出100多行的代码,自己还是有些欣慰的,从点到面 ...

  8. dedecms清空栏目后,新建ID不从1开始的解决方法

    在后台SQL运行器运行下面的语句,这样新建的栏目ID就从1开始了: ALTER TABLE `dede_arctype` AUTO_INCREMENT =1; (注意表名) 下面是文章的,运行后,发布 ...

  9. 最新消息,CDRX7冰点价再返现,你知道么?

    一年一度的七夕又到来了,这不很多的单身狗朋友们都已经自备好了狗粮,准备在家里宅上一天呢? 开个玩笑今天小编就为各位带来了 一个劲爆大消息... Deng/deng/deng/deng..就是备受万众瞩 ...

  10. Python 函数部分练习题

    函 数 基 础 1.写函数,,用户传入修改的文件名,与要修改的内容,执行函数,完成批了修改操作2.写函数,计算传入字符串中[数字].[字母].[空格] 以及 [其他]的个数 3.写函数,判断用户传入的 ...