luoguP2680 运输计划 题解(二分答案+树上差分)
P2680 运输计划 题目
这道题如果是看的我的树上差分来的,那么肯定一看题目就可以想到树上差分.
至于这是怎么想到的,一步一步来:
1.n有300000,不可能暴力枚举每一条边
2.因为我们要使运输时间的最大值最小,所以,考虑二分答案(做多了之后的习惯(其实也就是突然的灵感,不是必然......))
3.既然二分了答案,暂且把我们二分的答案变量名叫 lim ,考虑On的check():
想到每次把超过lim(跑LCA求运输计划的时间)的运输计划全部要考虑删边(显然),并且这些计划都必须要删一条公共边(也是显然,加虫洞就相当于把边权变为0,姑且叫做删边把),这就可以考虑差分了,把超过lim的计划全部差分进去,统计一下差分数组,枚举所有计划都经过的边(也就是差分数组==超过lim的计划数),看看最大的运输代价减去这个边权(相当于把它变为0,显然)是否小于lim, return1/0(显然最大值都小于lim了,所有的都小于lim了); 完成check()!
上代码:
- #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<<];
- struct ROAD{
- int fm,to,v;
- }road[N];
- int head[N],back[N];
- int cf[N];
- int deep[N],fa[N];
- int f[N][],g[N][];
- inline int read()
- {
- rg int s=,m=;rg char ch=getchar();
- while(ch!='-'&&(ch<''||ch>''))ch=getchar();
- if(ch=='-')m=-,ch=getchar();
- while(ch>=''&&ch<='')s=(s<<)+(s<<)+ch-'',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][]=fm;g[now][]=s;
- for(rg int i=;i<=;++i)
- {
- f[now][i]=f[f[now][i-]][i-];
- g[now][i]=g[f[now][i-]][i-]+g[now][i-];
- }
- 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+,edge[i].v);
- }
- }
- }
- inline int LCA(rg int x,rg int y,rg int op)//倍增跳LCA
- {
- rg int res=;
- if(deep[x]<deep[y])swap(x,y);
- while(deep[x]>deep[y])//跳到同样深度
- for(rg int i=;i>=;--i)
- if(deep[f[x][i]]>=deep[y])res+=g[x][i],x=f[x][i];
- while(x!=y)
- {
- for(rg int i=;i>=;--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][]+g[y][],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,);
- cf[p]++,cf[q]++,cf[lca]-=;
- }
- 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=,Max=;
- for(rg int i=;i<=n;++i)cf[i]=;
- for(rg int i=;i<=m;++i)
- {
- if(road[i].v>lim)
- {
- Max=max(Max,road[i].v);
- ss++,Insert(road[i].fm,road[i].to);
- }
- }
- sum();
- for(rg int i=;i<=n;++i)
- if(cf[i]==ss&&Max-edge[back[i]].v<=lim)return ;
- return ;
- }
- int main()
- {
- n=read(),m=read();
- for(rg int i=;i<n;++i)
- {
- rg int p=read(),q=read(),o=read();
- add(p,q,o),add(q,p,o);
- }
- //读入边的信息
- dfs(,,,);
- for(rg int i=;i<=m;++i)
- {
- rg int p=read(),q=read();
- road[i].fm=p,road[i].to=q,road[i].v=LCA(p,q,);
- ri=max(ri,road[i].v);
- }
- add(,,);//没事干加了一个 0->1 的边,感觉比较踏实(0的父亲是1)...无语...
- while(le<=ri)//二分
- {
- rg int mid=(ri+le)>>;
- if(check(mid))ans=mid,ri=mid-;
- else le=mid+;
- }
- printf("%d\n",ans);
- return ;
- }
luoguP2680 运输计划 题解(二分答案+树上差分)的更多相关文章
- luogu2680 [NOIp2015]运输计划 (tarjanLca+二分答案+树上差分)
我们先不会就二分一下答案,设它是x,我们要判断它能不能满足 为了满足这个答案,我们就要让原本路径长度大于x的所有路径都经过某条边,而且这条边还要大于等于最长的路径-x 于是运用树上差分的思想,对于所有 ...
- BZOJ 4326 NOIP2015 运输计划(二分答案 + 树上差分思想)
题目链接 BZOJ4326 这个程序在洛谷上TLE了……惨遭卡常 在NOIP赛场上估计只能拿到95分吧= = 把边权转化成点权 首先求出每一条路径的长度 考虑二分答案,$check(now)$ 对于 ...
- bzoj4326: NOIP2015 运输计划(二分+LCA+树上差分)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4326 题目大意:有一颗含有n个顶点的树,每两个点之间有一个边权,现在有m个运输计划,每个 ...
- LOJ2425 NOIP2015 运输计划 【二分+LCA+树上差分】*
LOJ2425 NOIP2015 运输计划 LINK 题意:给你一颗树,可以将任意一条边的权值变成0,然后求m条路径的长度的最小值 思路: 先二分最后的距离ans,然后我们把路程大于ans的所有路径拿 ...
- NOIP2015运输计划(二分答案)
题目描述 公元2044年,人类进入了宇宙纪元. L国有n个星球,还有n-1条双向航道,每条航道建立在两个星球之间,这n-1条航道连通了L国的所有星球. 小P掌管一家物流公司,该公司有很多个运输计划,每 ...
- [luogu]P2680 运输计划[二分答案][树上差分]
[luogu]P2680 [NOIP2015]运输计划 题目背景 公元 2044 年,人类进入了宇宙纪元. 题目描述 L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n ...
- luogu P2680 运输计划 (二分答案+树上差分)
题目背景 公元 20442044 年,人类进入了宇宙纪元. 题目描述 公元20442044 年,人类进入了宇宙纪元. L 国有 nn 个星球,还有 n-1n−1 条双向航道,每条航道建立在两个星球之间 ...
- loj2425 「NOIP2015」运输计划[二分答案+树上差分]
看到题意最小化最长路径,显然二分答案,枚举链长度不超过$\text{mid}$,然后尝试检验.````` 检验是否存在这样一个边置为0后,全部链长$\le\text{mid}$,其最终目标就是.要让所 ...
- 【BZOJ-4326】运输计划 树链剖分 + 树上差分 + 二分
4326: NOIP2015 运输计划 Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 703 Solved: 461[Submit][Status] ...
随机推荐
- elasticsearch 基础 —— ReIndex
Reindex会将一个索引的数据复制到另一个已存在的索引,但是并不会复制原索引的mapping(映射).shard(分片).replicas(副本)等配置信息. 一.reindex的常用操作 1.re ...
- 202-基于TI DSP TMS320C6678、Xilinx K7 FPGA XC72K325T的高速数据处理核心板
基于TI DSP TMS320C6678.Xilinx K7 FPGA XC72K325T的高速数据处理核心板 一.板卡概述 该DSP+FPGA高速信号采集处理板由我公司自主研发,包含一片TI DSP ...
- Codeforces 722E 组合数学 DP
题意:有一个n * m的棋盘,你初始在点(1, 1),你需要去点(n, m).你初始有s分,在这个棋盘上有k个点,经过一次这个点分数就会变为s / 2(向上取整),问从起点到终点的分数的数学期望是多少 ...
- Codeforces Round #584 - Dasha Code Championship - Elimination Round (rated, open for everyone, Div. 1 + Div. 2)
怎么老是垫底啊. 不高兴. 似乎 A 掉一道题总比别人慢一些. A. Paint the Numbers 贪心,从小到大枚举,如果没有被涂色,就新增一个颜色把自己和倍数都涂上. #include< ...
- Java打印流学习
打印流 打印流的主要功能是用于输出,在整个IO包打印流分为两种类型,打印流可以很方便的进行输出. 1.字节打印流:PrintStream(在字节输出时,可以增强输出功能) 2.字符打印流:PrintW ...
- 存储过程如何传变量到like下
存储过程中执行如下DDL语句create or replace procedure etl_test(v_com varchar2) is v_spname varchar2(40); com var ...
- redisTemplate 封装bitcout
@Repositorypublic class RedisServiceExtend { @Autowired private RedisTemplate<String, String> ...
- 分布式架构的CAP原理
CAP 定理的含义 一.分布式系统的三个指标 1998年,加州大学的计算机科学家 Eric Brewer 提出,分布式系统有三个指标. Consistency Availability Parti ...
- html中 的method=post和method=get的区别
1. get是从服务器上获取数据,post是向服务器传送数据. 2. get是把参数数据队列加到提交表单的ACTION属性所指的URL中,值和表单内各个字段一一对应,在URL中可以看到.post是通过 ...
- CDH6.3 Centos7
按照官方文档安装即可 CentOS7 上搭建 CDH(6.3.0) 官方文档:https://docs.cloudera.com/documentation/enterprise/6/6.3/topi ...