LuoguP2680/UOJ150[NOIP2015] 运输计划 解题报告【二分答案+树上操作(LCA)+树上差分】
2017-11-02 21:30
561 查看
题目背景
公元2044年,人类进入了宇宙纪元。
题目描述
L国有n个星球,还有n−1条双向航道,每条航道建立在两个星球之间,这n−1条航道连通了L国的所有星球。
小P掌管一家物流公司,该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 ui号星球沿最快的宇航路径飞行到vi号星球去。显然,飞船驶过一条航道 是需要时间的,对于航道j,任意飞船驶过它所花费的时间为tj,并且任意两艘飞船之 间不会产生任何干扰。
为了鼓励科技创新,L国国王同意小P的物流公司参与L国的航道建设,即允许小P把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。
在虫洞的建设完成前小P的物流公司就预接了m个运输计划。在虫洞建设完成后, 这m个运输计划会同时开始,所有飞船一起出发。当这m个运输计划都完成时,小P的物流公司的阶段性工作就完成了。
如果小P可以自由选择将哪一条航道改造成虫洞,试求出小P的物流公司完成阶段性工作所需要的最短时间是多少?
输入输出格式
输入格式:
输入文件名为 transport.in。
第一行包括两个正整数n、m,表示 L 国中星球的数量及小P公司预接的运输计划的数量,星球从1到n编号。
接下来n−1行描述航道的建设情况,其中第i行包含三个整数ai,bi和ti,表示第i 条双向航道修建在ai与bi两个星球之间,任意飞船驶过它所花费的时间为ti。
接下来m行描述运输计划的情况,其中第j行包含两个正整数uj和vj,表示第j个运输计划是从 uj号星球飞往vj号星球。
输出格式:
输出共1行,包含1个整数,表示小P的物流公司完成阶段性工作所需要的最短时间。
输入输出样例
输入样例#1:
6 3
1 2 3
1 6 4
3 1 7
4 3 6
3 5 5
3 6
2 5
4 5
输出样例#1:
11
说明
所有测试数据的范围和特点如下表所示
解题报告
题意就是在一棵树上,给定m个起点和终点,找一条边,把它的边权变为0,使得这m条路的最大值最小。
既然明确提到了“最大值最小”,考虑二分答案,二分路径的最大值,问题就在check上。我们假设有k条边小于二分出来的mid值,在这k条边上差分,具体的讲,就是在起点、终点上+1,在LCA上-2,计算每一个点的权值。对于点权为k的点,我们记录其到父亲之间连的边的最值vmax,最后用m条路径中的最大值w减去vmax,返回w-vmax<=mid。
具体实现上有一些细节问题:
我们可以预处理出每一条路径的长度(边权和:dis[u]+dis[v]−2∗dis[LCA(u,v)])、LCA,把他们按长度从大到小排序。
二分的边界应该是[0,p[1].w]。
总的来说,这道NOIP2015的题现在看起来也不是特别难,但是公认NOIP2015是NOIP近年来难度增加的一个转折点。现在回过头来看这个转折点上较难的题,还是有点意思。
代码如下:
公元2044年,人类进入了宇宙纪元。
题目描述
L国有n个星球,还有n−1条双向航道,每条航道建立在两个星球之间,这n−1条航道连通了L国的所有星球。
小P掌管一家物流公司,该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 ui号星球沿最快的宇航路径飞行到vi号星球去。显然,飞船驶过一条航道 是需要时间的,对于航道j,任意飞船驶过它所花费的时间为tj,并且任意两艘飞船之 间不会产生任何干扰。
为了鼓励科技创新,L国国王同意小P的物流公司参与L国的航道建设,即允许小P把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。
在虫洞的建设完成前小P的物流公司就预接了m个运输计划。在虫洞建设完成后, 这m个运输计划会同时开始,所有飞船一起出发。当这m个运输计划都完成时,小P的物流公司的阶段性工作就完成了。
如果小P可以自由选择将哪一条航道改造成虫洞,试求出小P的物流公司完成阶段性工作所需要的最短时间是多少?
输入输出格式
输入格式:
输入文件名为 transport.in。
第一行包括两个正整数n、m,表示 L 国中星球的数量及小P公司预接的运输计划的数量,星球从1到n编号。
接下来n−1行描述航道的建设情况,其中第i行包含三个整数ai,bi和ti,表示第i 条双向航道修建在ai与bi两个星球之间,任意飞船驶过它所花费的时间为ti。
接下来m行描述运输计划的情况,其中第j行包含两个正整数uj和vj,表示第j个运输计划是从 uj号星球飞往vj号星球。
输出格式:
输出共1行,包含1个整数,表示小P的物流公司完成阶段性工作所需要的最短时间。
输入输出样例
输入样例#1:
6 3
1 2 3
1 6 4
3 1 7
4 3 6
3 5 5
3 6
2 5
4 5
输出样例#1:
11
说明
所有测试数据的范围和特点如下表所示
解题报告
题意就是在一棵树上,给定m个起点和终点,找一条边,把它的边权变为0,使得这m条路的最大值最小。
既然明确提到了“最大值最小”,考虑二分答案,二分路径的最大值,问题就在check上。我们假设有k条边小于二分出来的mid值,在这k条边上差分,具体的讲,就是在起点、终点上+1,在LCA上-2,计算每一个点的权值。对于点权为k的点,我们记录其到父亲之间连的边的最值vmax,最后用m条路径中的最大值w减去vmax,返回w-vmax<=mid。
具体实现上有一些细节问题:
我们可以预处理出每一条路径的长度(边权和:dis[u]+dis[v]−2∗dis[LCA(u,v)])、LCA,把他们按长度从大到小排序。
二分的边界应该是[0,p[1].w]。
总的来说,这道NOIP2015的题现在看起来也不是特别难,但是公认NOIP2015是NOIP近年来难度增加的一个转折点。现在回过头来看这个转折点上较难的题,还是有点意思。
代码如下:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=300000,P=20; struct edge { int v,w,next; }ed[2*N+5]; struct path { int u,v,w,lca; friend bool operator <(const path &s,const path &r){return s.w>r.w;} }p[N+5]; int n,m,k,vmax; int head[N+5],num; int dep[N+5],anc[N+5][P+1],dis[N+5],mark[N+5]; void build(int u,int v,int w) { ed[++num].v=v; ed[num].w=w; ed[num].next=head[u]; head[u]=num; } void dfs_pre(int u,int f) { anc[u][0]=f; for (int p=1;p<=P;p++) anc[u][p]=anc[anc[u][p-1]][p-1]; for (int i=head[u];i!=-1;i=ed[i].next) { int v=ed[i].v; if (v==f) continue; dep[v]=dep[u]+1; dis[v]=dis[u]+ed[i].w; dfs_pre(v,u); } } int LCA(int u,int v) { if (dep[v]>dep[u]) swap(u,v); int t=dep[u]-dep[v]; for (int p=0;t;t>>=1,p++) if (t&1) u=anc[u][p]; if (u==v)return u; for(int p=P;p>=0;p--) if (anc[u][p]!=anc[v][p]) u=anc[u][p],v=anc[v][p]; return anc[u][0]; } void dfs(int u,int f) { for (int i=head[u];i!=-1;i=ed[i].next) { int v=ed[i].v; if(v==f)continue; dfs(v,u); mark[u]+=mark[v]; } if(mark[u]==k)vmax=max(vmax,dis[u]-dis[f]); } bool check(int mid) { k=0,vmax=0; memset(mark,0,sizeof(mark)); while(p[++k].w>mid&&k<=m) { int u=p[k].u,v=p[k].v,lca=p[k].lca; mark[u]++,mark[v]++,mark[lca]-=2; } k--; dfs(1,0); return p[1].w-vmax<=mid; } int main() { memset(head,-1,sizeof(head)); scanf("%d%d",&n,&m); for(int i=1;i<n;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); build(u,v,w),build(v,u,w); } dep[1]=1; dfs_pre(1,0); for(int i=1;i<=m;i++) { int u,v; scanf("%d%d",&u,&v); p[i].u=u,p[i].v=v,p[i].lca=LCA(u,v),p[i].w=dis[u]+dis[v]-2*dis[p[i].lca]; } sort(p+1,p+1+m); int lf=0,rg=p[1].w; while(lf+1<rg) { int mid=(lf+rg)>>1; if(check(mid))rg=mid; else lf=mid; } printf("%d",rg); return 0; }
相关文章推荐
- NOIP2015 运输计划 二分答案+Tarjan LCA+树上差分
- bzoj4326 & UOJ150【NOIP2015】运输计划 ( 树上差分 + lca )
- 【NOIP2015】运输计划(树上差分,二分答案)
- Noip2015 运输计划 【二分答案】【差分】【LCA】
- 洛谷 2680[NOIP2015] 运输计划 二分+lca+树上差分+dfs序
- [BZOJ4326][NOIP2015]运输计划(二分答案+树上差分)
- 【uoj#150】【NOIP2015】运输计划 树上前缀和+lca+二分+拓扑排序+特别的卡常数技巧
- 【bzoj 4326】【codevs 4632】【UOJ #150】[NOIP 2015]运输计划(dfs+lca+二分答案+差分)
- NOIP2015 运输计划 解题报告(二分答案+树状差分)
- 【二分+LCA差分乱搞】BZOJ4326(UOJ150) NOIP2015 运输计划
- bzoj4326【2015提高】运输计划(二分答案+lca+树上差分前缀和)
- 【BZOJ】4326 NOIP2015 运输计划 二分+LCA+树上差分
- LCA+二分+树上差分——Luogu2680 [NOIP2015]运输计划
- BZOJ 4326: NOIP2015 运输计划 二分答案 树上差分
- 【NOIP2015】运输计划 {二分答案+倍增+树上差分}
- Luogu 2680 NOIP 2015 运输计划(树链剖分,LCA,树状数组,树的重心,二分,差分)
- LuoguP1083 借教室[NOIP2012] 解题报告【二分答案+差分】
- NOIP 2015 Day 2 transport 运输计划 (树链剖分 序列差分 二分答案)
- BZOJ 4326 NOIP2015 运输计划 (二分+树上差分)
- bzoj 4326: NOIP2015 运输计划【树链剖分+二分+树上差分】