【SDOI2011 第2轮 DAY1】消防 -[树的直径+树链剖分][解题报告]
###[【SDOI2011 第2轮 DAY1】消防](http://oi.nks.edu.cn/zh/Problem/Details?cid=230&tid=C)
题面:
SDOI2011 第2轮 DAY1】消防 |
---|
时间限制 : 20000 MS 空间限制 : 565536 KB |
问题描述
时限\(2s\)
某个国家有\(n\)个城市,这\(n\)个城市中任意两个都连通且有唯一一条路径,每条连通两个城市的道路的长度为\(zi(zi<=1000)\)。
这个国家的人对火焰有超越宇宙的热情,所以这个国家最兴旺的行业是消防业。由于政府对国民的热情忍无可忍(大量的消防经费开销)可是却又无可奈何(总统竞选的国民支持率),所以只能想尽方法提高消防能力。
现在这个国家的经费足以在一条边长度和不超过\(s\)的路径(两端都是城市)上建立消防枢纽,为了尽量提高枢纽的利用率,要求其他所有城市到这条路径的距离的最大值最小。
你受命监管这个项目,你当然需要知道应该把枢纽建立在什么位置上。
输入格式
输入包含\(n\)行:
第\(1\)行,两个正整数\(n\)和\(s\),中间用一个空格隔开。其中\(n\)为城市的个数,\(s\)为路径长度的上界。设结点编号以此为\(,,,1,2,……,n\)。
从第\(2\)行到第\(n\)行,每行给出\(3\)个用空格隔开的正整数,依次表示每一条边的两个端点编号和长度。例如,“\(2 4 7\)”表示连接结点\(2\)与\(4\)的边的长度为\(7\)。
输出格式
输出包含一个非负整数,即所有城市到选择的路径的最大值,当然这个最大值必须是所有方案中最小的。
样例输入
【样例输入1】
5 2
1 2 5
2 3 2
2 4 4
2 5 3
【样例输入2】
8 6
1 3 2
2 3 2
3 4 6
4 5 3
4 6 4
4 7 2
7 8 3
样例输出
【样例输出1】
5
【样例输出2】
5
提示
【数据规模和约定】
对于\(20\%\)的数据,\(n<=300\)。
对于\(50\%\)的数据,\(n<=3000\)。
对于\(100\%\)的数据,\(n<=300000\),边长小等于\(1000\)。
题解:
最大值最小?二分答案?然而并不是这样写的;
本题采用贪心的做法;
显然我们选择的枢纽是在树的直径上的,而在这个基础上,我们希望我们选择的路径在合法的情况下尽量长;
于是我们用左右两个指针\(L,R\)从\(Pos[Root1]\)到\(Pos[Root2]\)移动,在移动的过程中,用L所指的节点到\(Root1\)的距离与\(R\)所指节点到\(Root2\)的距离以及\(L、R\)之间的点中,到直径外最大的距离这三者取\(max\)更新答案,保证答案最小;
对于第三个量,我们可以枚举直径上的起点,由于每个点显然最多遍历一次,所以预处理时间复杂度\(O(N)\),单调队列维护区间最大值就可以了;
因为偷懒,写了个树剖维护直径的\(DFS\)序连续,直接就变成在区间上扫一遍;
\(code:\)
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<ctype.h>
#include<vector>
#include<queue>
#include<cstring>
#include<map>
#include<cmath>
#include<stdlib.h>
#include<ctime>
#define lowbit(x) (x&-x)
#define ll long long
#define ld double
#define mod 998244353
using namespace std;
char buf[1<<20],*p1,*p2;
inline char gc()
{
// return getchar();
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin))==p1?0:*p1++;
}
template<typename T>
inline void read(T &x)
{
char tt;
bool flag=0;
while(!isdigit(tt=gc())&&tt!='-');
tt=='-'?(flag=1,x=0):(x=tt-'0');
while(isdigit(tt=gc())) x=x*10+tt-'0';
if(flag) x=-x;
}
struct node{
int x,len;
inline node(int a=0,int b=0)
{x=a,len=b;}
};
const int maxn=300002;
int n,s,root1,root2,mx;
int w[maxn],son[maxn];
int dfn[maxn],tot,pos[maxn];
int sum[maxn],id[maxn],q[maxn];
vector<node>G[maxn];
void dfs1(int x,int pre,ll dis)
{
for(int i=G[x].size()-1;i>=0;i--)
{
int p=G[x][i].x;
int len=G[x][i].len;
if(p==pre) continue;
dfs1(p,x,dis+len);
if(mx<dis+len) mx=dis+len,root1=p;
}
}
void dfs2(int x,int pre,ll dis)
{
sum[x]=dis;
for(int i=G[x].size()-1;i>=0;i--)
{
int p=G[x][i].x;
int len=G[x][i].len;
if(p==pre) continue;
w[p]=len;dfs2(p,x,dis+len);
if(mx<dis+len) mx=dis+len,root2=p;
if(w[p]>w[son[x]]) son[x]=p;
}
w[x]+=w[son[x]];
}
void dfs3(int x,int pre)
{
dfn[++tot]=x,pos[x]=tot;
if(!son[x]) return;
dfs3(son[x],x);
for(int i=G[x].size()-1;i>=0;i--)
{
int p=G[x][i].x;
if(p==pre||p==son[x]) continue;
dfs3(p,x);
}
}
void dfs(int x,int pre,int dis)
{
mx=max(mx,dis);
for(int i=G[x].size()-1;i>=0;i--)
{
int p=G[x][i].x,len=G[x][i].len;
if(p==pre||(pos[p]<=pos[root2]&&pos[p]>=pos[root1])) continue;
dfs(p,x,dis+len);
}
}
int head,tail;
int ans=1e9;
void modify(int x,int p)
{
while(tail>=head&&q[tail]<=x) tail--;
q[++tail]=x;id[tail]=p;
}
int main()
{
// freopen("1.txt","r",stdin);
// freopen("2.txt","w",stdout);
read(n),read(s);
for(int i=1;i<=n-1;i++)
{
int x,y,z;
read(x),read(y),read(z);
G[x].push_back(node(y,z));
G[y].push_back(node(x,z));
}
dfs1(1,1,0);mx=0;
dfs2(root1,root1,0);
memset(w,0,sizeof(w));
dfs3(root1,root1);
for(int i=pos[root1];i<=pos[root2];i++)
mx=0,dfs(dfn[i],0,0),w[dfn[i]]=mx;
// for(int i=1;i<=n;i++) printf("%d ",w[i]);
int l,r;
l=r=pos[root1];
while(l<=pos[root2])
{
while(id[head]<l&&head<=tail) head++;
while(r<=pos[root2]&&sum[dfn[r]]-sum[dfn[l]]<=s) modify(w[dfn[r]],r++);
// printf("%d\n",sum[dfn[r-1]-sum[dfn[l]]]);
ans=min(ans,max(max(sum[dfn[l++]]-sum[root1],sum[root2]-sum[dfn[r-1]]),q[head]));
}
// for(int i=1;i<=n;i++)
// printf("%d ",sum[i]);
printf("%d",ans);
}
【SDOI2011 第2轮 DAY1】消防 -[树的直径+树链剖分][解题报告]的更多相关文章
- [LOJ3014][JOI 2019 Final]独特的城市——树的直径+长链剖分
题目链接: [JOI 2019 Final]独特的城市 对于每个点,它的答案最大就是与它距离最远的点的距离. 而如果与它距离为$x$的点有大于等于两个,那么与它距离小于等于$x$的点都不会被计入答案. ...
- 树的统计Count---树链剖分
NEFU专项训练十和十一——树链剖分 Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t ...
- BZOJ 1036: [ZJOI2008]树的统计Count-树链剖分(点权)(单点更新、路径节点最值、路径求和)模板,超级认真写了注释啊啊啊
1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 23015 Solved: 9336[Submit ...
- 树的直径&树的重心
树的直径 定义 那么树上最远的两个点,他们之间的距离,就被称之为树的直径. 树的直径的性质 1. 直径两端点一定是两个叶子节点. 2. 距离任意点最远的点一定是直径的一个端点,这个基于贪心求直径方法的 ...
- 洛谷$P2486\ [SDOI2011]$染色 线段树+树链剖分
正解:线段树+树链剖分 解题报告: 传送门$QwQ$ 其实是道蛮板子的题,,,但因为我写得很呆然后写了贼久之后发现想法有问题要重构,就很难受,就先写个题解算了$kk$ 考虑先跑个树剖,然后按$dfn$ ...
- 【HDU 2196】 Computer(树的直径)
[HDU 2196] Computer(树的直径) 题链http://acm.hdu.edu.cn/showproblem.php?pid=2196 这题可以用树形DP解决,自然也可以用最直观的方法解 ...
- 树形DP 学习笔记(树形DP、树的直径、树的重心)
前言:寒假讲过树形DP,这次再复习一下. -------------- 基本的树形DP 实现形式 树形DP的主要实现形式是$dfs$.这是因为树的特殊结构决定的——只有确定了儿子,才能决定父亲.划分阶 ...
- bzoj 2282 [Sdoi2011]消防(树的直径,二分)
Description 某个国家有n个城市,这n个城市中任意两个都连通且有唯一一条路径,每条连通两个城市的道路的长度为zi(zi<=1000). 这个国家的人对火焰有超越宇宙的热情,所以这个国家 ...
- BZOJ 2243: [SDOI2011]染色 [树链剖分]
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 6651 Solved: 2432[Submit][Status ...
随机推荐
- 24.Linux-Nand Flash驱动(分析MTD层并制作NAND驱动)
1.本节使用的nand flash型号为K9F2G08U0M,它的命令如下: 1.1我们以上图的read id(读ID)为例,它的时序图如下: 首先需要使能CE片选 1)使能CLE 2)发送0X90命 ...
- Oracle中如何写存储过程
>存储过程是什么? 存储过程是一种命名的PL/SQL程序块,输入.输出参数数量[0个或多个],通常没有返回值[也有特殊的情况]. 运行SQL语句时,Oracle是要先编译再执行的:而存储过程是已 ...
- Java面试题—初级(9)
139. Java中的泛型是什么 ? 使用泛型的好处是什么? 泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数. 好处: 1.类型安全,提供编译期 ...
- 【16】命令模式(Command Pattern)
一.前言 最近项目中发现,对于设计模式的了解是必不可少的,当然对于设计模式的应用那更是重要,可以说是否懂得应用设计模式在项目中是衡量一个程序员的技术水平,因为对于一个功能的实现,高级工程师和初级工程师 ...
- ajax jsonp的跨域请求
1.页面ajax的请求 $.ajax({ async: false, url: 'http://localhost:8080/downloadVideos',//跨域的dns/document!sea ...
- codevs1735 方程的解数(meet in the middle)
题意 题目链接 Sol 把前一半放在左边,后一半放在右边 meet in the middle一波 统计答案的时候开始想的是hash,然而MLE了两个点 实际上只要排序之后双指针扫一遍就行了 #inc ...
- node 搭建静态服务
对于Node.js新手,搭建一个静态资源服务器是个不错的锻炼,从最简单的返回文件或错误开始,渐进增强,还可以逐步加深对http的理解. 基本功能 不急着写下第一行代码,而是先梳理一下就基本功能而言有哪 ...
- docker 开发常用命令总结
Docker 常用命令总结,镜像下载,到docker容器创建,常用docker命令的 增删查 1.镜像下载,从hub.docker.com中下载最新版本的postgres docker pull po ...
- FineReport单行与数据库交互的方法
1. 问题描述 我们在做一张报表填报的时候经常会遇到需要在一行进行添加动作,将该行数据直接与数据库交互,执行存储过程过程.我们可以通过每一行增加帆软“插入”按钮实现插入动作,并且在控件事件中增加和 ...
- 网络通信框架Retrofit2
网络通信框架Retrofit2 1 概要 Retrofit2的简介以及特点 Retrofit2使用配置(导包,权限等) Retrofit2中常用的注解介绍 Retrofit2实现http网络访问 GE ...