Vijos1983 NOIP2015Day2T3 运输计划 transport LCA




转载一个大佬的题解:
下面谈谈我的感悟:
当然写代码也是写的很艰辛:
我力劝C++的同胞们,这题卡常数,Dfs党会吃亏,比如这里这个UOJ的数据
我们可以使用Bfs和尽量避免写Dfs,不然会Tle的
以下代码实测极端数据约900ms,正所谓卡常数,如果把一开始的dfs改为bfs可能会更快……(博主很懒,不改了)
总结一下大佬的题解:
1. Dfs或Bfs构建树,然后记录下各种信息,现在主要是以下几点:
1)子节点 son[rt] vector <int>
2)深度 deep[rt] int
3)到根节点的距离 dis[rt] int
4)到父亲节点的距离 fadis[rt] int
5)父亲 father[rt] int
2. LCA的预处理,处理出F[rt][i],表示节点rt的第2i个祖先(即节点rt的祖先中与之深度相差rt的祖先) // F[rt][i] 在代码中写成 Anst[rt][i]
转移表达式为:F[rt][i]=F[F[rt][i-1]][i-1] 应该都能够理解
3. 求取LCA: 这里用的倍增的方法,虽然比离线算法LCA_Tarjan慢一个log,但是倍增是一个好东西,不妨去练练。这样思考:对于两个深度为d的节点a和b,使得int i=log2(d),那么就可以倍增:对于节点a和b,如果他们的第2i个祖先是相同的,那么他们在网上的祖先也一定是相同的 ,那么我们就对于不改变a和b的值,而使i=i-1;如果他们的第2i个祖先不同,那么他们往下走的祖先也是不同的,于是就可以确定他们的最近公共祖先一定是在第2i个祖先上面的,那么我们就可以安心的把a和b的值更新乘F[a][i]和F[b][i](a=F[a][i],b=F[b][i])。直到i为0位置,无法再做了。于是,a和b的最近公共祖先就是a和b的父亲,即F[a][0]或F[b][0](相等的)。于是剩下的只是把a和b调到同一深度这点事情了。设b为深度更大的那个,设deep[x]为x的深度,那么把b移上去,就是求b个第(deep[b]-deep[a])个祖先,也是倍增可以解决的。
至于LCA_Tarjan,可以自己学啊!这里就不多说了。
3.二分答案:不用说了吧,就是一个基本的二分
4.check(答案):这个在大佬的题解里面写的比较详细,可以看他的~
#pragma comment(linker, "/STACK:10240000,10240000")
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <vector>
using namespace std;
const int N=+,M=N*,Inf=N*;
void read(int &x){
x=;
char ch=getchar();
while (!(''<=ch&&ch<=''))
ch=getchar();
while (''<=ch&&ch<=''){
x=x*+ch-;
ch=getchar();
}
}
struct Edge{
int cnt,y[M],z[M],nxt[M],fst[N];
void set(){
cnt=;
memset(y,,sizeof y);
memset(z,,sizeof z);
memset(nxt,,sizeof nxt);
memset(fst,,sizeof fst);
}
void add(int a,int b,int c){
cnt++;
y[cnt]=b,z[cnt]=c;
nxt[cnt]=fst[a],fst[a]=cnt;
}
}e;
int n,m;
vector <int> Tree[N];
int father[N],son[N],deep[N],dis[N],fadis[N],bh[N],bhtot;
int Anst[N][];//Ancestor
struct Query{
int x,y,LCA,cost;
}q[N];
int Nextsum[N];
void Build_Tree(int prev,int rt){
bh[++bhtot]=rt;
Tree[rt].clear();
deep[rt]=deep[prev]+;
son[rt]=;
father[rt]=prev;
for (int i=e.fst[rt];i;i=e.nxt[i])
if (e.y[i]!=prev){
son[rt]++,Tree[rt].push_back(e.y[i]);
fadis[e.y[i]]=e.z[i];
dis[e.y[i]]=dis[rt]+e.z[i];
Build_Tree(rt,e.y[i]);
}
}
void LCA_Prepare(){
memset(Anst,,sizeof Anst);
for (int i=;i<=n;i++){
int rt=bh[i];
Anst[rt][]=father[rt];
for (int i=;(<<i)<=deep[rt];i++)
Anst[rt][i]=Anst[Anst[rt][i-]][i-];
}
}
int LCA(int a,int b){
if (deep[a]>deep[b])
swap(a,b);
for (int i=deep[b]-deep[a],j=;i>;i>>=,j++)
if (i&)
b=Anst[b][j];
if (a==b)
return a;
int k;
for (k=;(<<k)<=deep[a];k++);
for (;k>=;k--)
if ((<<k)<=deep[a]&&Anst[a][k]!=Anst[b][k])
a=Anst[a][k],b=Anst[b][k];
return Anst[a][];
}
bool check(int t){
int total=,Maxcost=,Maxcut=;
memset(Nextsum,,sizeof Nextsum);
for (int i=;i<=m;i++)
if (q[i].cost>t){
Maxcost=max(Maxcost,q[i].cost-t);
total++;
Nextsum[q[i].x]++;
Nextsum[q[i].y]++;
Nextsum[q[i].LCA]-=;
}
for (int i=n;i>=;i--)
Nextsum[father[bh[i]]]+=Nextsum[bh[i]];
for (int i=;i<=n;i++)
if (Nextsum[i]==total)
Maxcut=max(Maxcut,fadis[i]);
return Maxcost<=Maxcut;
}
int main(){
scanf("%d%d",&n,&m);
e.set();
for (int i=;i<n;i++){
int a,b,c;
read(a),read(b),read(c);
e.add(a,b,c);
e.add(b,a,c);
}
bhtot=;
deep[]=-,dis[]=fadis[]=;
Build_Tree(,);
LCA_Prepare();
for (int i=;i<=m;i++){
read(q[i].x),read(q[i].y);
q[i].LCA=LCA(q[i].x,q[i].y);
q[i].cost=dis[q[i].x]+dis[q[i].y]-dis[q[i].LCA]*;
}
int le=,ri=Inf,mid,ans=;
while (le<=ri){
mid=(le+ri)>>;
if (check(mid))
ri=mid-,ans=mid;
else
le=mid+;
}
printf("%d",ans);
return ;
}
代码
Vijos1983 NOIP2015Day2T3 运输计划 transport LCA的更多相关文章
- P2680 运输计划[二分+LCA+树上差分]
题目描述 公元20442044 年,人类进入了宇宙纪元. L 国有 nn 个星球,还有 n-1n−1 条双向航道,每条航道建立在两个星球之间,这 n-1n−1 条航道连通了 LL 国的所有星球. 小 ...
- noip 2015 运输计划 (lca+二分)
/* 95 最后一个点T了 qian lv ji qiong 了 没学过树剖 听chx听xzc说的神奇的方法 Orz 首先求出每个计划的路径长度 这里写的倍增 然后二分答案 对于每个ans 统计> ...
- NOIP2015Day2T3运输计划(二分+树上差分)
做了这么多NOIPTG的题,这是唯一 一道一眼秒的T3(有时候T2还不会做QAQ)... 题目大意就不说了QWQ 思路大概是:啊最大值最小化,来个二分.检验mid的话,显然就是用最长路径减去所有边权& ...
- [luoguP2680] 运输计划(lca + 二分 + 差分)
传送门 暴力做法 50 ~ 60 枚举删边,求最大路径长度的最小值. 其中最大路径长度运用到了lca 我们发现,求lca的过程已经不能优化了,那么看看枚举删边的过程能不能优化. 先把边按照权值排序,然 ...
- Noip2015Day2T3 运输计划
题目链接 problem 一棵n个点带边权的树,有m个条路径.选择一条边,将其权值变为0,使得长度最长的路径长度最小.求该长度最小为多少. solution 其实仔细一想并不难. 删除一条边会导致所有 ...
- 洛谷P2680 运输计划(倍增LCA + 树上差分 + 二分答案)
[题目链接] [思路]: 根据题意可以明显看出,当所有任务都完成时的时间是最终的结果,也就是说本题要求,求出最小的最大值. 那这样的话就暗示了将答案二分,进行check. [check方法]: 如果说 ...
- UOJ150 运输计划
运输计划(transport.cpp/c/pas)[问题描述]公元 2044 年,人类进入了宇宙纪元.L 国有 n 个星球,还有 n-1 条 双向 航道,每条航道建立在两个星球之间,这 n-1 条航道 ...
- 【NOIP 2015 DAY2 T3】 运输计划 (树链剖分-LCA)
题目背景 公元 2044 年,人类进入了宇宙纪元. 题目描述 L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n-1 条航道连通了 L 国的所有星球. 小 P 掌管一家 ...
- NOIP2015 运输计划(二分+LCA+差分)
4326: NOIP2015 运输计划 Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 308 Solved: 208[Submit][Status] ...
随机推荐
- Java中instanceof与getClass的区别
在比较一个类和另一个类是否属于同一个类实例的时候,通常可以采用instanceof和getClass两种方法比较两者是否相等来判断,但是两者在判断上面是有差别的,下面通过代码说明: public cl ...
- windows修复分区卷:chkdsk
问题描述: 共享磁盘上传文件到服务器报错:一个意外错误使你无法复制该文件夹.如果你继续收到此错误,可以使用错误代码来搜索有关问题的帮助,错误 0x800703E3:由于线程退出或应用程序请求,已终止I ...
- css 样式 记录
/* Track */::-webkit-scrollbar-track { -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); -webkit-bo ...
- Android&Java面试题大全—金九银十面试必备
声明本文由作者:Man不经心授权转载,转载请联系原文作者原文链接:https://www.jianshu.com/p/375ad14096b3, 类加载过程 Java 中类加载分为 3 个步骤:加载. ...
- Java对象之间的深度复制拷贝
/* * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETA ...
- iOS项目国际化详解
现在的开发中难免会遇到项目国际化处理,下面把我理解到的国际化相关的知识点进行总结归纳 1 首先是对项目名称,系统性的文字进行名字化,比如程序名字 1,先给项目添加语言 2 添加InfoPlist.st ...
- libopencv_highgui.so.2.4.9:对‘TIFFReadRGBAStrip@LIBTIFF_4.0’未定义的引用
make之前加上sudo su重新make即可 http://blog.csdn.net/cfyzcc/article/details/52981467
- axis 数据流
产生数据流的代码 模板 重新修改了下 :]axis_data_cnt='d0; :]axis_data_frame_cnt='d0; :]delay_cnt='d0; initial begin ...
- SpringBoot全局日志管理(AOP)
1.在pom.xml中引入aop的jar包 <dependency> <groupId>org.springframework.boot</groupId> < ...
- WEB漏洞 XSS(一)
1.xss的形成原理 xss 中文名是“跨站脚本攻击”,英文名“Cross Site Scripting”.xss也是一种注入攻击,当web应用对用户输入过滤不严格,攻击者写入恶意的脚本代码(HTML ...