题目:BZOJ4326、洛谷P2680、Vijos P1983、UOJ#150、codevs4632、codevs5440。

题目大意:有一棵带权树,有一些运输计划,第i个运输计划从ai到bi,耗时为ai到bi的距离,所有运输计划一起开始。现在可以把一条边权变成0,求最终运输计划最短要多少时间。

解题思路:标算是树剖,然而我并不会……

我的方法是LCA+二分+树上差分。

首先LCA,求出每个运输计划的长度,可一遍dfs求出每个节点到根的距离dist,则a到b的长度为dist[a]+dist[b]-(dist[lca(a,b)]<<1)。

接着二分答案,然后判断答案可行性。

对于每一个答案,我们要找的是所有长度大于当前答案的运输计划的公共边,因为只有所有长度大于当前答案的运输计划全部变成小于等于当前答案,当前答案才可行。

用树上差分(不懂请百度)。我们用s[i]记录i到它父亲这条边有多少计划经过。

对于每个运输计划,如果长度大于当前答案,我们给s[a]+1,s[b]+1,s[lca(a,b)]-2,因为我们要统计的是边,所以对于两个点,lca(a,b)对应的边实际是没有走到的,所以-2。

差分完后判断答案可行性即可。

我用倍增时间复杂度为$O(m\log_2 n+(n+m)\log_2 len)$,len为运输计划的最大长度。

但常数巨大,1s很容易被卡,因此有些地方还过不掉。例如我在UOJ上就被卡97。但在时限较宽或数据较弱的地方还是能AC的。

C++ Code:

%:pragma GCC optimize(2)
#include<cstdio>
#include<cctype>
#include<cstring>
using namespace std;
char buf[10700005];
int bufpos,n,m,head[300001],deep[300001],p[300001][21],dist[300001],s[300001],fa_edge[300001],mx,now;
struct edge{int to,dis,nxt;
}e[600003];
struct que{int a,b,len,LCA;
}f[300001];
inline int max(int a,int b){return(a>b)?a:b;}
inline int readint(){char c=buf[bufpos++];for(;!isdigit(c);c=buf[bufpos++]);int p=0;for(;isdigit(c);c=buf[bufpos++])p=(p<<3)+(p<<1)+(c^'0');return p;
}
void dfs(int s){for(int i=head[s];i;i=e[i].nxt)if(!deep[e[i].to]){fa_edge[e[i].to]=i;deep[e[i].to]=deep[s]+1;p[e[i].to][0]=s;dist[e[i].to]=dist[s]+e[i].dis;dfs(e[i].to);}
}
int lca(int x,int y){if(deep[x]<deep[y])x^=y^=x^=y;int i;for(i=0;(1<<i)<=deep[x];++i);--i;for(int j=i;j>-1;--j)if(deep[p[x][j]]>=deep[y])x=p[x][j];if(x==y)return x;for(int j=i;j>-1;--j)if(p[x][j]!=-1&&p[x][j]!=p[y][j])x=p[x][j],y=p[y][j];return p[x][0];
}
void updata(int now){for(int i=head[now];i;i=e[i].nxt)if(deep[now]<deep[e[i].to]){updata(e[i].to);s[now]+=s[e[i].to];}
}
bool ok(int ans){memset(s,0,sizeof s);int gz=0;for(int i=1;i<=n;++i)if(f[i].len>ans){++gz;++s[f[i].a];++s[f[i].b];s[f[i].LCA]-=2;}updata(1);for(int i=1;i<=m;++i)if(s[i]==gz&&mx-ans<=e[fa_edge[i]].dis)return true;return false;
}
int main(){buf[fread(buf,1,10700000,stdin)]=bufpos=0;m=readint(),n=readint();for(int i=1;i<m;++i){int from=readint(),to=readint(),dis=readint();now=i<<1;e[now-1]=(edge){to,dis,head[from]};head[from]=now-1;e[now]=(edge){from,dis,head[to]};head[to]=now;}memset(p,-1,sizeof p);dist[1]=0;deep[1]=1;dfs(1);for(int j=1;(1<<j)<=m;++j)for(int i=1;i<=m;++i)if(p[i][j-1]!=-1)p[i][j]=p[p[i][j-1]][j-1];int l=0,r=0,mid;for(int i=1;i<=n;++i){f[i].a=readint();f[i].b=readint();f[i].LCA=lca(f[i].a,f[i].b);r=max(r,f[i].len=dist[f[i].a]+dist[f[i].b]-(dist[f[i].LCA]<<1));}mx=r;++r;while(l<r){mid=l+r>>1;if(ok(mid))r=mid;elsel=mid+1;}printf("%d\n",r);return 0;
}

倍增时间复杂度比较高,我改成用Tarjan求LCA,速度瞬间变快,在UOJ上成功卡了过去。不过codevs4632仍然被卡。

以下为Tarjan代码。

C++ Code:

%:pragma GCC optimize(2)
#include<cstdio>
#include<cctype>
#include<cstring>
using namespace std;
char buf[10700005];
int bufpos,n,m,head[300001],deep[300001],dist[300001],s[300001],fa_edge[300001],mx,now,headq[300001],nq=0;
bool vis[300001];
int fa[300001];
struct edge{int to,dis,nxt;
}e[600003];
struct que{int a,b,len,LCA;
}f[300001];
struct Query{int same,nxt,to,num;bool flag;
}q[600003];
int find(int x){return(fa[x]==x)?x:(fa[x]=find(fa[x]));}
inline int max(int a,int b){return(a>b)?a:b;}
inline int readint(){char c=buf[bufpos++];for(;!isdigit(c);c=buf[bufpos++]);int p=0;for(;isdigit(c);c=buf[bufpos++])p=(p<<3)+(p<<1)+(c^'0');return p;
}
void dfs(int s){for(int i=head[s];i;i=e[i].nxt)if(!deep[e[i].to]){fa_edge[e[i].to]=i;deep[e[i].to]=deep[s]+1;dist[e[i].to]=dist[s]+e[i].dis;dfs(e[i].to);}
}
void tarjan(int root){for(int i=head[root];i;i=e[i].nxt)if(deep[root]<deep[e[i].to]){tarjan(e[i].to);fa[e[i].to]=root;vis[e[i].to]=true;}for(int i=headq[root];i;i=q[i].nxt)if(vis[q[i].to]&&!q[i].flag){q[i].flag=q[q[i].same].flag=true;f[q[i].num].LCA=find(q[i].to);}
}
void updata(int now){for(int i=head[now];i;i=e[i].nxt)if(deep[now]<deep[e[i].to]){updata(e[i].to);s[now]+=s[e[i].to];}
}
bool ok(int ans){memset(s,0,sizeof s);int gz=0;for(int i=1;i<=n;++i)if(f[i].len>ans){++gz;++s[f[i].a];++s[f[i].b];s[f[i].LCA]-=2;}updata(1);for(int i=1;i<=m;++i)if(s[i]==gz&&mx-ans<=e[fa_edge[i]].dis)return true;return false;
}
int main(){buf[fread(buf,1,10700000,stdin)]=bufpos=0;m=readint(),n=readint();for(int i=1;i<m;++i){int from=readint(),to=readint(),dis=readint();now=i<<1;e[now-1]=(edge){to,dis,head[from]};head[from]=now-1;e[now]=(edge){from,dis,head[to]};head[to]=now;fa[i]=i;}fa[m]=m;deep[1]=1;dfs(1);int l=0,r=0,mid;for(int i=1;i<=n;++i){f[i].a=readint();f[i].b=readint();int& x=f[i].a,&y=f[i].b;q[++nq].to=y;q[nq].same=nq+1;q[nq].num=i;q[nq].nxt=headq[x];headq[x]=nq;q[++nq].to=x;q[nq].same=nq-1;q[nq].num=i;q[nq].nxt=headq[y];headq[y]=nq;if(x==y)q[nq].flag=q[nq-1].flag=true,f[i].LCA=x;}tarjan(1);for(int i=1;i<=n;++i)r=max(r,f[i].len=dist[f[i].a]+dist[f[i].b]-(dist[f[i].LCA]<<1));mx=r;++r;while(l<r){mid=l+r>>1;if(ok(mid))r=mid;elsel=mid+1;}printf("%d\n",r);return 0;
}

转载于:https://www.cnblogs.com/Mrsrz/p/7635580.html

[NOIP2015提高组]运输计划相关推荐

  1. P2678 [NOIP2015 提高组] 跳石头

    P2678 [NOIP2015 提高组] 跳石头 题目背景 一年一度的"跳石头"比赛又要开始了! 题目描述 这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石.组委会已经选 ...

  2. 信息学奥赛一本通 1890:【15NOIP提高组】跳石头 | 洛谷 P2678 [NOIP2015 提高组] 跳石头

    [题目链接] ybt 1890:[15NOIP提高组]跳石头 洛谷 P2678 [NOIP2015 提高组] 跳石头 ybt 1247:河中跳房子 OpenJudge NOI 1.11 10:河中跳房 ...

  3. 洛谷-神奇的幻方-NOIP2015提高组复赛

    题目描述 幻方是一种很神奇的N*N矩阵:它由数字1,2,3,--,N*N构成,且每行.每列及两条对角线上的数字之和都相同. 当N为奇数时,我们可以通过以下方法构建一个幻方: 首先将1写在第一行的中间. ...

  4. P2615 [NOIP2015 提高组] 神奇的幻方

    题目描述 幻方是一种很神奇的 N\times NN×N 矩阵:它由数字 1,2,3,\cdots \cdots ,N \times N1,2,3,⋯⋯,N×N 构成,且每行.每列及两条对角线上的数字之 ...

  5. 【NOIP2015提高组】信息传递

    题目背景 NOIP2015 提高组 Day1 T2 题目描述 有 n 个同学(编号为1到n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为 i 的同学的信息传递对象是编 ...

  6. [NOIP2015 提高组] 神奇的幻方 ——C++

    [NOIP2015 提高组] 神奇的幻方 题目描述 幻方是一种很神奇的 N∗NN*NN∗N 矩阵:它由数字 1,2,3,⋯⋯ ,N×N1,2,3,\cdots \cdots ,N \times N1, ...

  7. [NOIP2015 提高组] 神奇的幻方

    题目描述 幻方是一种很神奇的 N*NN∗N 矩阵:它由数字 1,2,3,\cdots \cdots ,N \times N1,2,3,⋯⋯,N×N 构成,且每行.每列及两条对角线上的数字之和都相同. ...

  8. 跳石头 NOIP2015 提高组 Day2 T1

    codevs 4768 跳石头 题目描述 Description 一年一度的"跳石头"比赛又要开始了! 这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石.组委会已经选择好 ...

  9. 【题解】P2678 [NOIP2015 提高组] 跳石头

    题目背景 一年一度的"跳石头"比赛又要开始了! 题目描述 这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石.组委会已经选择好了两块岩石作为比赛起点和终点.在起点和终点之间 ...

最新文章

  1. parasoft Jtest 使用教程:创建并使用参数化测试用例(上)
  2. seata xid是什么_Seata 分布式事务框架
  3. 大量词云出现的时候IO的负担很大
  4. java toolkit invoker_有没有哪位老哥愿意帮一下新人啊
  5. P3357 最长k可重线段集问题 网络流
  6. webdriver---API---(java版) 高级应用
  7. 马云融资80亿美金的“资本”
  8. python获取session里的_python 怎么取sessionid-问答-阿里云开发者社区-阿里云
  9. 人工智能之入门大数据
  10. 【NeurIPS2020】之预训练语言模型压缩
  11. 使用PC版Zune以全新的方式体验您的音乐
  12. 在线小说网站的设计与实现(附源码)
  13. 数据库、模式、表的关系(转载)
  14. hdu 3987 最小割边数模板题
  15. FPGA Verilog HDL 系列实例--------双向移位寄存器
  16. 2021-Swin Transformer Attention机制的详细推导
  17. 图片base64转码,本地和网络图片均可,类对象转map,类对象转键值对字符串
  18. 2022年三网融合行业研究报告
  19. iPhone开发实战 pdf电子书
  20. diy谷蜂Y5刷机包--基于官方0207稳定版

热门文章

  1. 嵌入式linux 自动获取IP 及 自动校时
  2. 您的光纤电缆和测试仪是否准备好用于400G以太网?
  3. 机房内综合布线电缆的紧密捆绑有哪些问题?
  4. 后端技术:MyBatis动态SQL写法介绍
  5. SQLServer常用的配置函数笔记
  6. 后端:循环遍历的用法介绍
  7. 计算机系统基础:校验码知识笔记
  8. Redis为何这么快?
  9. python 多继承的问题
  10. 有一种爱情叫永不改变_设计就像爱情一样,总是在寻找一种方式