NOIP2015 D2T3 洛谷2680 BZOJ4326 运输计划 解题报告
前言:个人认为这是历年NOIP中比较简单的最后一题了,因此将自己的思路与大家分享。
题目大意:
给一棵无根树,给出m条路径。允许将树上的一条边的权值改为0。求m条路径长度最大值的最小值。n,m<=300000.
思考:
题目将40分部分分给了链的情况。50分的部分分给了n,m<=3000.说明以下两点:
1.链的情况可能是问题的突破口(类比NOIP2016D1T2的部分分设置)。
2.可能要从较小的n,m入手(经验之谈:当n,m较小有30分时大多情况是为了分数好看,但n,m较小有50-80分则是启发正解)
那么我们将问题简化成一条链。
对链的情况的分析:
当树退化成链的时候,我们可以将树用链表保存。为了简单起见,我们用映射数组m将链表中距离链头i个结点的编号映射成i+1。链头的编号为1。这样可以将链表保存在普通的数组里,而不是有nxt域的数组。
下文用m(i)表示原来第i个结点的映射。
对于任意询问u,v,必然是从数组的第min(m(v),m(u))个元素到第max(m(u),m(v))个元素。我们可以通过前缀和在O(n)预处理,O(1)的时间获得答案。这样我们得到了未删除边的答案m个。
现在我们要减少一条边的权值到0。不难发现减少的边一定在得到最大答案的路径上。但不一定是得到最大答案的路径上边权最大的边。原因呢?
分析答案式:
最终答案ans=max(w(l1),w(l2),...,w(lm)).w(l)为路径l的长度。当我们减掉的边是最大答案路径上边权最大的边时,答案可能受到次大答案路径的影响。当我们减掉最大答案路径和次大答案路径的交上的最大边时,答案可能受到第三大答案路径的影响。由此分析,答案可能是要减去最大答案路径的最大值,最大答案路径和次大答案路径的交集的最大值,...,所有路径交集的最大值之一。在模拟样例的过程中,我们可以发现答案应该随着上述删除边的变化逐渐变小或不变。若答案变大则可以停止向下查找。
继续链上的分析:
网上的题解大多借着答案的单调性以及要求最大值最小,想到了二分答案。在链上时间复杂度为O(m*logmax).
我比较蠢,没看出来二分答案。我来谈谈我在链上的做法。
将数组放在线段树上,线段树保存三个data。第一个是区间最大值maxx。第二个是区间被所有路径覆盖的最大值chs,第三个是区间最大覆盖次数mxcv。对于任意的l到r。给l到r这一段的区间最大覆盖次数加一。查找操作时如果mxcv不等于当前枚举的路径数量则直接return。否则返回chs。时间复杂度O(mlogn)。
放在树上:
链上的情况解决了,那么树上就很容易了。树链剖分后将问题退化至链上即可解决,时间复杂度需要加一个log,为O(mlognlogn)。
但是不知道为什么我的用时比树上前缀和的O(nlogmaxn)要快
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = ;
struct edge{int to,w,nxt;}e[maxn<<],get_LCA[maxn<<];
struct node{int mxcv,maxx,chs,lazy;}t[maxn<<];
struct ask{int from,to,LCA,len;}Pro[maxn],*P=Pro;
int n,m,NM,NM2,g[maxn],top[maxn],fa[maxn],sz[maxn],son[maxn],ABOUT_LCA[maxn];
int pre[maxn],dep[maxn],call[maxn],abcall[maxn],tms[maxn],FW[maxn],stnd=,l,r;
int found(int x){
int rx = x; while(pre[rx]!=rx)rx=pre[rx];
while(pre[x]!=rx){int t=pre[x];pre[x]=rx;x=t;}
return rx;
}
void dfs1(int now,int Prt,int DPTH){//Prt=parent //as we get fa,size,depth,Father_road_weight,we can also get LCA
fa[now] = Prt;dep[now] = DPTH;int maxx = ;
for(int i=ABOUT_LCA[now];i;i=get_LCA[i].nxt){
if(!fa[get_LCA[i].to])continue;
Pro[get_LCA[i].w].LCA = found(get_LCA[i].to);
}
for(int i=g[now];i;i=e[i].nxt){
if(e[i].to==Prt)continue;
dfs1(e[i].to,now,DPTH+e[i].w);
sz[now]+=sz[e[i].to];FW[e[i].to]=e[i].w;
if(sz[maxx]<sz[e[i].to])maxx=e[i].to;
}
sz[now]++;son[now] = maxx;
pre[found(now)] = found(Prt);
}
void dfs2(int now,int tp,int Val){
if(tp != now) NM++,call[now] = NM,abcall[NM]=Val;
top[now] = tp;
if(son[now]) dfs2(son[now],tp,FW[son[now]]);
for(int i=g[now];i;i=e[i].nxt){
if(e[i].to == son[now] || e[i].to == fa[now])continue;
dfs2(e[i].to,e[i].to,e[i].w);
}
}
void build_tree(int l,int r,int now){
if(l == r) t[now].chs=t[now].maxx=abcall[l];
else{
int mid = (l+r)/;
build_tree(l,mid,now<<),build_tree(mid+,r,now<<|);
t[now].maxx = t[now].chs = max(t[now<<].maxx,t[now<<|].maxx);
}
}
void add_edge(int a,int b,int v,int NUM[],int &u,edge NE[]){
NE[++u] = (edge){b,v,NUM[a]}; NUM[a] = u;
NE[++u] = (edge){a,v,NUM[b]}; NUM[b] = u;
}
void read(){
scanf("%d%d",&n,&m);
for(int i=,a,b,v;i<n;i++){scanf("%d%d%d",&a,&b,&v);add_edge(a,b,v,g,NM,e);}
for(int i=;i<=m;i++){scanf("%d%d",&Pro[i].from,&Pro[i].to);}
for(int i=;i<=m;i++){add_edge(Pro[i].from,Pro[i].to,i,ABOUT_LCA,NM2,get_LCA);}
}
void Heavy_Lt_Dec(){
for(int i=;i<=n;i++) pre[i] = i;
dfs1(,-,); NM=; dfs2(,,); build_tree(,NM,);
}
void push_up(int now){
t[now].mxcv = max(t[now<<].mxcv,t[now<<|].mxcv);
if(t[now<<].mxcv > t[now<<|].mxcv)t[now].chs=t[now<<].chs;
else if(t[now<<].mxcv < t[now<<|].mxcv)t[now].chs=t[now<<|].chs;
else t[now].chs = max(t[now<<].chs,t[now<<|].chs);
}
void push_down(int now){
t[now<<].lazy+=t[now].lazy;t[now<<|].lazy+=t[now].lazy;
t[now<<].mxcv+=t[now].lazy;t[now<<|].mxcv+=t[now].lazy;
t[now].lazy=;
}
int update(int tl,int tr,int now){
if(t[now].mxcv < stnd- || l>tr || r<tl)return ;
if(tl >= l && tr <= r){t[now].mxcv++;t[now].lazy++;return t[now].chs;}
if(t[now].lazy) push_down(now);
int mid=(tl+tr)/,ans=max(update(tl,mid,now*),update(mid+,tr,now*+));
push_up(now);
return ans;
}
int ADD_Tree(int OP,int ED,int PB){
int ans = ;
while(OP != PB){
l=call[son[top[OP]]],r=call[OP];int kkk = top[OP];
if(top[OP]==top[PB])l=call[son[PB]],kkk=PB;
if(top[OP]==OP){if(++tms[OP]==stnd)ans=max(ans,FW[OP]);OP=fa[OP];}
else{ans=max(ans,update(,NM,));OP=kkk;}
}
while(ED != PB){
l=call[son[top[ED]]],r=call[ED];int kkk = top[ED];
if(top[ED]==top[PB])l=call[son[PB]],kkk=PB;
if(top[ED]==ED){if(++tms[ED]==stnd)ans=max(ans,FW[ED]);ED=fa[ED];}
else{ans=max(ans,update(,NM,));ED=kkk;}
}
return ans;
}
int cmp(ask a,ask b){return a.len<b.len;}
void work(){
for(int i=;i<=m;i++)Pro[i].len=dep[P[i].from]+dep[P[i].to]-*dep[P[i].LCA];
sort(Pro+,Pro+m+,cmp);int maxans = Pro[m].len;
for(int i=m;i>=;i--,stnd++){
int ans = max(P[m].len-ADD_Tree(P[i].from,P[i].to,P[i].LCA),P[i-].len);
if(ans > maxans)break; else maxans = ans;
}
printf("%d",maxans);
}
int main(){read();Heavy_Lt_Dec();work();return ;}
NOIP2015 D2T3 洛谷2680 BZOJ4326 运输计划 解题报告的更多相关文章
- 洛谷 P4292 [WC2010]重建计划 解题报告
P4292 [WC2010]重建计划 题目描述 \(X\)国遭受了地震的重创, 导致全国的交通近乎瘫痪,重建家园的计划迫在眉睫.\(X\)国由\(N\)个城市组成, 重建小组提出,仅需建立\(N-1\ ...
- 洛谷_Cx的故事_解题报告_第四题70
1.并查集求最小生成树 Code: #include <stdio.h> #include <stdlib.h> struct node { long x,y,c; ...
- 洛谷 P2680 运输计划 解题报告
P2680 运输计划 题目背景 公元2044年,人类进入了宇宙纪元. 题目描述 公元2044年,人类进入了宇宙纪元. \(L\)国有\(n\)个星球,还有\(n-1\)条双向航道,每条航道建立在两个星 ...
- 洛谷 P2317 [HNOI2005]星际贸易 解题报告
P2317 [HNOI2005]星际贸易 题目描述 输入输出格式 输入格式: 输出格式: 如果可以找到这样的方案,那么输出文件output.txt中包含两个整数X和Y.X表示贸易额,Y表示净利润并且两 ...
- 洛谷 P3802 小魔女帕琪 解题报告
P3802 小魔女帕琪 题目背景 从前有一个聪明的小魔女帕琪,兴趣是狩猎吸血鬼. 帕琪能熟练使用七种属性(金.木.水.火.土.日.月)的魔法,除了能使用这么多种属性魔法外,她还能将两种以上属性组合,从 ...
- 洛谷 P2606 [ZJOI2010]排列计数 解题报告
P2606 [ZJOI2010]排列计数 题目描述 称一个\(1,2,...,N\)的排列\(P_1,P_2...,P_n\)是\(Magic\)的,当且仅当对所以的\(2<=i<=N\) ...
- 洛谷1303 A*B Problem 解题报告
洛谷1303 A*B Problem 本题地址:http://www.luogu.org/problem/show?pid=1303 题目描述 求两数的积. 输入输出格式 输入格式: 两个数 输出格式 ...
- 【洛谷P2680】运输计划
题目链接 题目大意: 一棵\(n\)个点的带边权的数,给定\(m\)条树上两点间的路径,现在你可以让树上任意一条边的权值变为零, 问如何选边使得\(m\)条路径中边权和最大的路径的边权和最小 \(\m ...
- 「洛谷P3469」[POI2008]BLO-Blockade 解题报告
P3469[POI2008]LO-Blockade 题意翻译 在Byteotia有n个城镇. 一些城镇之间由无向边连接. 在城镇外没有十字路口,尽管可能有桥,隧道或者高架公路(反正不考虑这些).每两个 ...
随机推荐
- 转:【web前端开发】浏览器兼容性处理大全
解决思路: ①.写代码的时候遵循W3C标准,按照最新稳定版本的IE或WebKit内核浏览器进行编码 ②.遇到部分无法全面解决浏览器兼容的时候,采取CSS的hack手段进行针对性微调.简单的说,CSS ...
- Appium疑难杂症
坑之初体验 在Appium的初体验中,遇到了一些坑坑洼洼.将他们记录下来,以后方便查阅. 1. session大于60秒没接收到命令自动关闭 通过Appium-Python-Client连接到appi ...
- SQL总结手册
1.SQL语法 (1)查询 SQL查询是使用最多的,需要凭借结构.索引和字段类型等因素.大多数据库含有一个优化器(optimizer),把用户查询转换为可选形式,以提高查询效率. 基本语法为: SEL ...
- 转 Caffe学习系列(4):激活层(Activiation Layers)及参数
在激活层中,对输入数据进行激活操作(实际上就是一种函数变换),是逐元素进行运算的.从bottom得到一个blob数据输入,运算后,从top输入一个blob数据.在运算过程中,没有改变数据的大小,即输入 ...
- webpack打包速度和性能再次优化
一. 改单dll为双dll 因为上图原因,使用CommonsChunkPlugin时,导致其打包出来的vendors.js内的模块ID会因为其他文件引用模块数量的变化而变化. 所以现利用DllPlug ...
- 提升R代码运算效率的11个实用方法——并行、效率
转载于36大数据,原文作者:Selva Prabhakaran 译者:fibears 众所周知,当我们利用R语言处理大型数据集时,for循环语句的运算效率非常低.有许多种方法可以提升你的代码运算效率 ...
- 小说接入UC浏览器内核技术对话(二)
质辛@灿岩 质辛跟我们说一下那个删除文件的逻辑吧质辛@灿岩 应该不是删除cache下所有文件吧?质辛质辛@智鹰 提供一下我们的临时文件完整路径给 灿岩吧质辛@智鹰 是负责我们ucsdk的 技术对 ...
- hi3531 SDK 编译 uboot, 修改PHY地址, 修改 uboot 参数 .
一,编译uboot SDK文档写得比较清楚了,写一下需要注意的地方吧. 1. 之前用SDK里和别人给的已经编译好的uboot,使用fastboot工具都刷不到板子上.最后自己用SDK里uboot源码编 ...
- freemarker写select组件报错总结(二)
1.错误描述 六月 25, 2014 11:32:49 下午 freemarker.log.JDK14LoggerFactory$JDK14Logger error 严重: Template proc ...
- live555编译环境
Ⅰ live555简介 Live555 是一个为流媒体提供解决方案的跨平台的C++开源项目,它实现了对标准流媒体传输协议如RTP/RTCP.RTSP.SIP等的支持.Live555实现了对多种音视频编 ...