运输计划(题解)(Noip2015)

二分答案+树上差分

树上差分其实不难,只是名字高大尚,可以学一下:Eternal风度的树上差分

本人博客里也总结了一些其他的知识供大家学习:Eternal风度的博客

具体解答

至于这是怎么想到的,一步一步来:

1.n有300000,不可能暴力枚举每一条边

2.因为我们要使运输时间的最大值最小,所以,考虑二分答案(做多了之后的习惯(其实也就是突然的灵感,不是必然......))

3.既然二分了答案,暂且把我们二分的答案变量名叫 lim ,考虑On的check():

  • 想到每次把超过lim(跑LCA求运输计划的时间)的运输计划全部要考虑删边(显然),并且这些计划都必须要删一条公共边(也是显然,加虫洞就相当于把边权变为0,姑且叫做删边把)
  • 这就可以考虑差分了,把超过lim的计划全部差分进去,统计一下差分数组,枚举所有计划都经过的边(也就是差分数组==超过lim的计划数),看看最大的运输代价减去这个边权(相当于把它变为0,显然)是否小于lim(如果最大值都小于lim了,所有的都小于lim了)

上代码:

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<iomanip>
#include<ctime>
#include<queue>
#include<stack>
#define rg register
#define lst long long
#define N 300050
using namespace std; int n,m,cnt,ans,maxn,le,ri;
struct EDGE{
int to,v,nxt;
}edge[N<<1];
struct ROAD{
int fm,to,v;
}road[N];
int head[N],back[N];
int cf[N];
int deep[N],fa[N];
int f[N][25],g[N][25]; inline int read()
{
rg int s=0,m=1;rg char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')m=-1,ch=getchar();
while(ch>='0'&&ch<='9')s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
return s*m;
} inline void add(rg int p,rg int q,rg int o)
{
edge[++cnt].to=q,edge[cnt].v=o;
edge[cnt].nxt=head[p];
head[p]=cnt;
} void dfs(rg int now,rg int fm,rg int dep,rg int s)//dfs预处理倍增LCA
{
fa[now]=fm,deep[now]=dep;
f[now][0]=fm;g[now][0]=s;
for(rg int i=1;i<=20;++i)
{
f[now][i]=f[f[now][i-1]][i-1];
g[now][i]=g[f[now][i-1]][i-1]+g[now][i-1];
}
for(rg int i=head[now];i;i=edge[i].nxt)
{
rg int qw=edge[i].to;
if(qw!=fm)
{
back[qw]=i;
dfs(qw,now,dep+1,edge[i].v);
}
}
} inline int LCA(rg int x,rg int y,rg int op)//倍增跳LCA
{
rg int res=0;
if(deep[x]<deep[y])swap(x,y);
while(deep[x]>deep[y])//跳到同样深度
for(rg int i=20;i>=0;--i)
if(deep[f[x][i]]>=deep[y])res+=g[x][i],x=f[x][i]; while(x!=y)
{
for(rg int i=20;i>=0;--i)
if(f[x][i]!=f[y][i])
res+=g[x][i]+g[y][i],x=f[x][i],y=f[y][i]; if(fa[x]==fa[y])res+=g[x][0]+g[y][0],x=y=fa[x];
}
if(!op)return res;
else return x;
} inline void Insert(rg int p,rg int q)//差分
{
rg int lca=LCA(p,q,1);
cf[p]++,cf[q]++,cf[lca]-=2;
} void sum(rg int now)//统计差分数组
{
for(rg int i=head[now];i;i=edge[i].nxt)
{
rg int qw=edge[i].to;
if(qw!=fa[now])
{
sum(qw);
cf[now]+=cf[qw];
}
}
} inline int check(rg int lim)//如解析,check()
{
rg int ss=0,Max=0;
for(rg int i=1;i<=n;++i)cf[i]=0;
for(rg int i=1;i<=m;++i)
{
if(road[i].v>lim)
{
Max=max(Max,road[i].v);
ss++,Insert(road[i].fm,road[i].to);
}
}
sum(0);
for(rg int i=1;i<=n;++i)
if(cf[i]==ss&&Max-edge[back[i]].v<=lim)return 1;
return 0;
} int main()
{
n=read(),m=read();
for(rg int i=1;i<n;++i)
{
rg int p=read(),q=read(),o=read();
add(p,q,o),add(q,p,o);
}
//读入边的信息
dfs(1,0,1,0);
for(rg int i=1;i<=m;++i)
{
rg int p=read(),q=read();
road[i].fm=p,road[i].to=q,road[i].v=LCA(p,q,0);
ri=max(ri,road[i].v);
}
add(0,1,0);//没事干加了一个 0->1 的边,感觉比较踏实(0的父亲是1)...无语...
while(le<=ri)//二分
{
rg int mid=(ri+le)>>1;
if(check(mid))ans=mid,ri=mid-1;
else le=mid+1;
}
printf("%d\n",ans);
return 0;
}

运输计划(题解)(Noip2015)的更多相关文章

  1. [NOIP2015 提高组] 运输计划题解

    题目链接:P2680 [NOIP2015 提高组] 运输计划 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 看了好长时间题解才终于懂的,有关lca和二分答案的题解解释的不详细,一时 ...

  2. NOIP2015运输计划题解报告

    这题在洛谷上可以找到提交 P2680运输计划 题目背景 公元 2044 年,人类进入了宇宙纪元. 题目描述 L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n-1 条航 ...

  3. [NOIP2015]运输计划 题解

    题目背景 公元 2044 年,人类进入了宇宙纪元. 题目描述 L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n-1 条 航道连通了 L 国的所有星球. 小 P 掌管一 ...

  4. luoguP2680 运输计划 题解(二分答案+树上差分)

    P2680 运输计划  题目 这道题如果是看的我的树上差分来的,那么肯定一看题目就可以想到树上差分. 至于这是怎么想到的,一步一步来: 1.n有300000,不可能暴力枚举每一条边 2.因为我们要使运 ...

  5. 题解 [NOIP2015]运输计划

    题解 [NOIP2015]运输计划 题面 解析 首先肯定是要求出每条路径的长度. 这个用节点到根的前缀和就行了(一开始脑抽写了个线段树...) 然后有一个显然的类似贪心的想法, 就是你改造的边肯定在最 ...

  6. NOIP2015 运输计划(bzoj4326)

    4326: NOIP2015 运输计划 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 886  Solved: 574[Submit][Status] ...

  7. [BZOJ4326][codevs4632][codevs5440][UOJ#150][NOIP2015]运输计划

    [BZOJ4326][codevs4632][codevs5440][UOJ#150][NOIP2015]运输计划 试题描述 公元 2044 年,人类进入了宇宙纪元. L 国有 n 个星球,还有 n− ...

  8. [NOIP2015]运输计划 D2 T3 LCA+二分答案+差分数组

    [NOIP2015]运输计划 D2 T3 Description 公元2044年,人类进入了宇宙纪元. L国有n个星球,还有n-1条双向航道,每条航道建立在两个星球之间,这n-1条航道连通了L国的所有 ...

  9. 【NOIP2015】运输计划

    [NOIP2015]运输计划 标签: 树上差分 LCA 二分答案 Description 公元 2044 年,人类进入了宇宙纪元. L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星 ...

随机推荐

  1. python 简易小爬虫

    此脚本用于爬站点的下载链接,最终输出到txt文档中. 如果是没有防盗链设置的站点,也可以使用脚本中的下载函数尝试直接下载. 本脚本是为了短期特定目标设计的,如果使用它爬其它特征的资源链接需自行修改配置 ...

  2. js url传参,参数加密

    前台 function encode64(input) { var output = ""; var base = new Base64(); var output = base. ...

  3. Python之文件的读

    python中文件的读操作:以只读的形式打开文件->逐行读取文件中的内容->关闭文件 代码如下 #文件的读 f = file(u'F:\\python\\homework.txt', 'r ...

  4. 【记录】git error:bad signature 解决方法

    今天提交git 的时候出现 bad signature 错误,意思是git下的index文件损坏了,需要重新生成下 error: bad signature fatal: index file cor ...

  5. 线程池-连接池-JDBC实例-JDBC连接池技术

    线程池和连接池   线程池的原理:     来看一下线程池究竟是怎么一回事?其实线程池的原理很简单,类似于操作系统中的缓冲区的概念,它的流程如下:先启动若干数量的线程,并让这些线程都处于睡眠状态,当客 ...

  6. [Usaco2007 Jan]Telephone Lines架设电话线(最短路,二分)

    [Usaco2007 Jan]Telephone Lines架设电话线 Description FarmerJohn打算将电话线引到自己的农场,但电信公司并不打算为他提供免费服务.于是,FJ必须为此向 ...

  7. uiautomatorviewer不能直接截取手机屏幕信息

    本身可以用sdk——>tools里自带的ui automator viewer截取如果截取不了,采用以下方法: 新建一个文本文档,名字自己起如uni.bat(注意把后缀给改成.bat) adb ...

  8. Tunnel connection failed: 407 Proxy Authentication Required

    报错信息 : Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connecti ...

  9. thinkphp model

    模型样板 <?php namespace app\model; use think\Db; use think\Model; class Admin extends Model { //表名 p ...

  10. jmeter性能工具 之 传参 (三)

    jmeter 主要有三种方式:键值对传参,json格式传参,外部传参 1.键值对传参 可以参考上篇登陆,使用的传参方式是键值对传参  2.json 格式传参 用json 格式传参不要忘了加http 头 ...