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] ...
随机推荐
- Tomcat服务的安装及配置
在进行Java Web开发时必须有Web服务器的支持,常用的Web服务器便是Tomcat,本文主要介绍Tomcat的安装和配置.客户端通过Web浏览器发送一个基于HTTP协议的请求到服务器上后,服务器 ...
- Laravel 5.2--改变数据库字段值,编辑时候,默认选中
模型 <?php namespace App\Models; use App\Helpers\ImageHelper; use App\Libraries\Nestedset\NodeTrait ...
- appium常用方法
1.输入中文 在capabilities中增加两项设置: capabilities.setCapability("unicodeKeyboard", "True" ...
- git 创建分支
- 13)django-ORM(连表一对多,外键创建,创建数据,3种查询)
一对多需要使用外键 一:外键创建ForeignKey b=models.ForeignKey(to="Business",to_field=("id"))#dj ...
- 整理六百篇web前端知识混总
9个有用的和免费的工具来支持动态网页开发 8个基本的引导工具的网页设计师 11款CSS3动画工具的开发 2016年某前端群题目答案参考 9最好的JavaScript压缩工具 创建响应式布局的10款优秀 ...
- (转)scikit-learn主要模块和基本使用方法
从网上看到一篇总结的很不错的sklearn使用文档,备份勿忘. 引言 对于一些开始搞机器学习算法有害怕下手的小朋友,该如何快速入门,这让人挺挣扎的.在从事数据科学的人中,最常用的工具就是R和Pytho ...
- 点击<a>标签后禁止页面跳至顶部
一.点击<a>标签后禁止页面跳至顶部 1. 使用 href="javascript:void(0);",例如: <a href="javascript: ...
- iis配置问题
最近调试程序时发现一直用的是vs自带的服务器 当我切换成iis时,发现虽然能显示界面,却连不上数据库 (程序数据库的一系列操作是通过wcf ria完成的) 以前在winserver2012上也遇到过这 ...
- 简化版的AXI-LITE4和配合使用的RTL
////////////////////////////////////////////////////////////////////////////////// // // The ZYNQ FI ...