NOIP2015运输计划(二分答案)
题目描述
公元2044年,人类进入了宇宙纪元。
L国有n个星球,还有n-1条双向航道,每条航道建立在两个星球之间,这n-1条航道连通了L国的所有星球。
小P掌管一家物流公司,该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从ui号星球沿最快的宇航路径飞行到vi号星球去。显然,飞船驶过一条航道是需要时间的,对于航道j,任意飞船驶过它所花费的时间为tj,并且任意两艘飞船之间不会产生任何干扰。
为了鼓励科技创新,L国国王同意小P的物流公司参与L国的航道建设,即允许小P把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。
在虫洞的建设完成前小P的物流公司就预接了m个运输计划。在虫洞建设完成后,这m个运输计划会同时开始,所有飞船一起出发。当这m个运输计划都完成时,小P的物流公司的阶段性工作就完成了。
如果小P可以自由选择将哪一条航道改造成虫洞,试求出小P的物流公司完成阶段性工作所需要的最短时间是多少?
输入格式
第一行包括两个正整数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的物流公司完成阶段性工作所需要的最短时间。
input
6 3
1 2 3
1 6 4
3 1 7
4 3 6
3 5 5
3 6
2 5
4 5
output
11
样例说明
将第1条航道改造成虫洞:则三个计划耗时分别为:11、12、11,故需要花费的时间为12。
将第2条航道改造成虫洞:则三个计划耗时分别为:7、15、11,故需要花费的时间为15。
将第3条航道改造成虫洞:则三个计划耗时分别为:4、8、11,故需要花费的时间为11。
将第4条航道改造成虫洞:则三个计划耗时分别为:11、15、5,故需要花费的时间为15。
将第5条航道改造成虫洞:则三个计划耗时分别为:11、10、6,故需要花费的时间为11。
故将第3条或第5条航道改造成虫洞均可使得完成阶段性工作的耗时最短,需要花费的时间为11。
限制与约定
解题思路:
首先考虑一下暴力,在n,m都小于3000时,先将两点间的边权值转化为深度较大的点的权值,利用朴素LCA求出两点间的耗费时间,再枚举删去哪一点枚举m中答案,更新即可
时间复杂度O(n*m),期望得分60分
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long lnt;
struct pnt{
int hd;
int no;
int fa;
int ol;
int dp;
lnt val;
}p[];
struct ent{
int twd;
int lst;
lnt tim;
}e[];
int cnt;
int n,m;
lnt ans=0x7f7f7f7f7f7f7f7fll;
int u[];
int v[];
int tf[];
int hv[][];
void ade(int f,int t,lnt y)
{
cnt++;
e[cnt].twd=t;
e[cnt].lst=p[f].hd;
p[f].hd=cnt;
e[cnt].tim=y;
}
void dfs(int x,int f)
{
p[x].dp=p[f].dp+;
p[x].fa=f;
for(int i=p[x].hd;i;i=e[i].lst)
{
int to=e[i].twd;
if(to!=f)
{
p[to].val=e[i].tim;
dfs(to,x);
}
}
return ;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<n;i++)
{
int a,b;
lnt c;
scanf("%d%d%lld",&a,&b,&c);
ade(a,b,c);
ade(b,a,c);
}
dfs(,);
for(int i=;i<=m;i++)
{
scanf("%d%d",&u[i],&v[i]);
}
if(m==)
{
lnt mtmp=;
lnt mins=;
int x=u[];
int y=v[];
if(p[x].dp<p[y].dp)
swap(x,y);
while(p[x].dp!=p[y].dp)
{
mtmp+=p[x].val;
mins=max(mins,p[x].val);
x=p[x].fa;
}
if(x==y)
{
printf("%lld\n",mtmp-mins);
return ;
}
while(x!=y)
{
mins=max(mins,p[x].val);
mins=max(mins,p[y].val);
mtmp+=p[x].val;
x=p[x].fa;
mtmp+=p[y].val;
y=p[y].fa;
}
printf("%lld\n",mtmp-mins);
return ;
}
for(int i=;i<=m;i++)
{
lnt mtmp=;
int x=u[i];
int y=v[i];
if(p[x].dp<p[y].dp)
swap(x,y);
while(p[x].dp!=p[y].dp)
{
hv[i][x]=;
mtmp+=p[x].val;
x=p[x].fa;
}
if(x==y)
{
tf[i]=mtmp;
continue;
}
while(x!=y)
{
hv[i][x]=;
hv[i][y]=;
mtmp+=p[x].val;
x=p[x].fa;
mtmp+=p[y].val;
y=p[y].fa;
}
tf[i]=mtmp;
}
for(int i=;i<=n;i++)
{
lnt maxs=;
for(int j=;j<=m;j++)
{
maxs=max(maxs,tf[j]-(lnt)hv[j][i]*p[i].val);
}
ans=min(ans,maxs);
}
printf("%lld\n",ans);
return ;
}
正解:
二分答案+树上打差分
将计划排序。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long lnt;
struct pnt{
int fa;
int dp;
int hd;
int ola;
int sgrl;
lnt dis;
}p[];
struct ent{
int twd;
int lst;
lnt vls;
}e[];
struct qnt{
int u;
int v;
lnt dtc;
}q[];
int n,m;
int cnt;
int ont;
int lsd;
int top;
int old[][];
int lg[];
int lns[];
int lfs[];
bool cmp(qnt x,qnt y)
{
return x.dtc>y.dtc;
}
void ade(int f,int t,lnt v)
{
cnt++;
e[cnt].twd=t;
e[cnt].lst=p[f].hd;
e[cnt].vls=v;
p[f].hd=cnt;
}
void dfs_build(int x,int f)
{
old[][++ont]=x;
p[x].fa=f;
p[x].dp=p[f].dp+;
p[x].ola=ont;
bool flag=;
for(int i=p[x].hd;i;i=e[i].lst)
{
int to=e[i].twd;
if(to!=f)
{
flag=false;
p[to].dis=p[x].dis+e[i].vls;
dfs_build(to,x);
old[][++ont]=x;
}
}
if(flag)
{
lfs[++lsd]=x;
}
}
void Tr_dfs(int x,int f)
{
for(int i=p[x].hd;i;i=e[i].lst)
{
int to=e[i].twd;
if(to!=f)
{
Tr_dfs(to,x);
p[x].sgrl+=p[to].sgrl;
}
}
return ;
}
int rmaxs(int x,int y)
{
return p[x].dp>p[y].dp?y:x;
}
int lca(int x,int y)
{
if(p[x].ola>p[y].ola)
swap(x,y);
int lgg=lg[p[y].ola-p[x].ola+];
return rmaxs(old[lgg][p[x].ola],old[lgg][p[y].ola-(<<lgg)+]);
}
int Ccl(int agc)
{
int x=;
while(agc<q[x+].dtc)x++;
if(lns[x])return lns[x];
for(int i=;i<=n;i++)
p[i].sgrl=;
for(int i=;i<=x;i++)
{
p[q[i].u].sgrl++;
p[q[i].v].sgrl++;
p[lca(q[i].v,q[i].u)].sgrl-=;
}
Tr_dfs(,);
lnt ans=;
for(int i=;i<=n;i++)
{
if(p[i].sgrl==x)
{
ans=max(ans,p[i].dis-p[p[i].fa].dis);
}
}
lns[x]=ans;
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<n;i++)
{
int x,y;
int z;
scanf("%d%d%d",&x,&y,&z);
ade(x,y,z);
ade(y,x,z);
}
for(int i=;i<=*n;i++)
{
lg[i]=lg[i/]+;
}
dfs_build(,);
for(int i=;i<=;i++)
for(int j=;j+(<<i)-<=ont;j++)
old[i][j]=rmaxs(old[i-][j],old[i-][j+(<<i-)]);
for(int i=;i<=m;i++)
{
scanf("%d%d",&q[i].u,&q[i].v);
q[i].dtc=p[q[i].u].dis+p[q[i].v].dis-*p[lca(q[i].v,q[i].u)].dis;
}
sort(q+,q+m+,cmp);
int l=;
int r=q[].dtc;
int ans;
while(l<=r)
{
int mid=(l+r)>>;
if(q[].dtc-Ccl(mid)>mid)l=mid+;
else{
ans=mid;
r=mid-;
}
}
printf("%d\n",ans);
return ;
}
NOIP2015运输计划(二分答案)的更多相关文章
- 【bzoj4326】[NOIP2015]运输计划 二分答案+LCA
题目描述 公元 2044 年,人类进入了宇宙纪元.L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所有星球.小 P 掌管一家物流公司, 该 ...
- BZOJ 4326 NOIP2015 运输计划 (二分+树上差分)
4326: NOIP2015 运输计划 Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 1930 Solved: 1231[Submit][Statu ...
- [luogu]P2680 运输计划[二分答案][树上差分]
[luogu]P2680 [NOIP2015]运输计划 题目背景 公元 2044 年,人类进入了宇宙纪元. 题目描述 L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n ...
- loj2425 「NOIP2015」运输计划[二分答案+树上差分]
看到题意最小化最长路径,显然二分答案,枚举链长度不超过$\text{mid}$,然后尝试检验.````` 检验是否存在这样一个边置为0后,全部链长$\le\text{mid}$,其最终目标就是.要让所 ...
- luogu P2680 运输计划 (二分答案+树上差分)
题目背景 公元 20442044 年,人类进入了宇宙纪元. 题目描述 公元20442044 年,人类进入了宇宙纪元. L 国有 nn 个星球,还有 n-1n−1 条双向航道,每条航道建立在两个星球之间 ...
- vijos 运输计划 - 二分答案 - 差分 - Tarjan
Description 公元 2044 年,人类进入了宇宙纪元.L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所有星球.小 P 掌管一家 ...
- BZOJ 4326: NOIP2015 运输计划(二分,树上差分)
Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 1945 Solved: 1243[Submit][Status][Discuss] Descript ...
- 运输计划[二分答案 LCA 树上差分]
也许更好的阅读体验 \(\mathcal{Description}\) 原题链接 概括一下题意 给一颗有\(n\)个点带边权的树,有\(m\)个询问,每次询问\(u,v\)两点间的权值和,你可以将树中 ...
- NOIP2015 运输计划 - 二分 + 树链剖分 / (倍增 + 差分)
BZOJ CodeVS Uoj 题目大意: 给一个n个点的边带权树,给定m条链,你可以选择树中的任意一条边,将它置为0,使得最长的链长最短. 题目分析: 最小化最大值,二分. 二分最短长度mid,将图 ...
- cogs2109 [NOIP2015] 运输计划
cogs2109 [NOIP2015] 运输计划 二分答案+树上差分. STO链剖巨佬们我不会(太虚伪了吧 首先二分一个答案,下界为0,上界为max{路径长度}. 然后判断一个答案是否可行,这里用到树 ...
随机推荐
- Objective-C学习笔记(十)——循环语句for和do-while的使用
在OC中.除了while这样的循环方式外,还有另外for循环和do-while循环.它们在不同的业务逻辑下会有不同的作用.能够和C语言和Java对照着学习. (一)代码一: int main(int ...
- Android 4.3 系统裁剪——删除不使用的app及添加自己app
删除不使用的apk 系统自带的app位置是在/android4.3/packages/apps 以下是一些APP作用分析: | |– BasicSmsReceiver | |– Bluetooth ( ...
- Intent传递对象——Serializable和Parcelable差别
前两篇文章讨论了Serializable和Parcelable实现Intent之间传递对象和对象数组的方式.两种方法实现上相似,效果一致,怎么选择用哪种方法实现呢? Intent在不同的组件中传递对象 ...
- C++包含头文件时尖括号和双引号区别
原文链接:http://c.biancheng.net/cpp/biancheng/view/66.html 如果你还看一些别的C++教程,那么你可能很早就发现了,有些书上的#include命令写作# ...
- XML获取节点信息值
XmlDocument doc = new XmlDocument(); doc.LoadXml(sreturn); XmlNode xNode = doc.SelectSingleNode(&quo ...
- openSUSE leap 42.3 添加HP Laserjet Pro M128fn打印机和驱动
一.安装驱动 YaST控制中心->软件管理->搜索->hplip 安装hplip 如下图: HPLIP(Linux Imaging and Printing Object)以前有hp ...
- Linux 终端仿真程序Putty
PuTTY是一个Telnet.SSH.rlogin.纯TCP以及串行接口连接软件.较早的版本仅支持Windows平台,现在的版本中开始支持各类Unix平台. 用linux作为桌面系统,身为工程师很多时 ...
- window.location.href和window.top.location.href的区别
if (window.location.href == window.top.location.href) { window.top.location.href = "/index. ...
- 紫书 例题 9-9 UVa 10003 (区间dp+递推顺序)
区间dp,可以以一个区间为状态,f[i][j]是第i个切点到第j个切点的木棍的最小费用 那么对于当前这一个区间,枚举切点k, 可以得出f[i][j] = min{dp(i, k) + dp(k, j) ...
- 【Henu ACM Round#16 A】 Bear and Game
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 看看什么时候t[i]-t[i-1]>15. 输出t[i-1]+15就好. 不存在这样的i就输出min(t[n]+15,90) ...