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] ...
随机推荐
- CURL错误代码及含义
https://curl.haxx.se/libcurl/c/libcurl-errors.html NAME libcurl-errors - error codes in libcurl DESC ...
- Django 笔记(四)模板标签 ~ 自定义过滤器
模板标签: 标签在渲染的过程中提供任意的逻辑 语法: 由{% ... %} 和 {% end... %} 常用标签: with:类似取别名 模版继承: Django模版引擎中最强大也是最复杂的部分就是 ...
- 分布式系统的一致性协议之 2PC 和 3PC
在分布式系统领域,有一个理论,对于分布式系统的设计影响非常大,那就是 CAP 理论,即对于一个分布式系统而言,它是无法同时满足 Consistency(强一致性).Availability(可用性) ...
- HTML_1
HTML 指的是超文本标记语言: HyperText Markup LanguageHTML 不是一种编程语言,而是一种标记语言标记语言是一套标记标签 (markup tag)HTML 使用标记标签来 ...
- ios 手机端 input 框上方有内阴影
解决方案 方法1: <!--如果 ui 样式里有边框,可以用外层盒子设置边框--> input{ border:none; } 方法2: //在IOS下,input 和textarea表单 ...
- 初学python之路-day14
一.带参装饰器 # 通常,装饰器为被装饰的函数添加新功能,需要外界的参数 # -- outer参数固定一个,就是func # -- inner参数固定同被装饰的函数,也不能添加新参数 # -- 可以借 ...
- Confluence 6 配置避免管理员联系表单垃圾
你可以配置 Confluence 使用验证码(Captcha)来避免垃圾内容发送给 Confluence 管理员.有关管理员联系表单验证码的内容在全站验证码设置中进行配置,相关的文档请参考 Confi ...
- 用json获取拉钩网的信息
class LaoGo(object): def __init__(self): self.url="http://www.lagou.com/lbs/getAllCitySearchLab ...
- Tomcat解决中文乱码并部署项目
1.在Tomcat下的server.xml中添加URIEncoding="UTF-8"(解决中文乱码的问题) 2.在Tomcat下的server.xml中添加<Context ...
- Django知识点汇总
Python的WEB框架有Django.Tornado.Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了ORM.模型绑定.模板引擎.缓存.Session等诸多功能. ...