博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
P2680 运输计划
阅读量:5316 次
发布时间:2019-06-14

本文共 2306 字,大约阅读时间需要 7 分钟。

十分显然完成工作的时间和航耗时最长的运输计划有关

所以题目意思就是要求最大值最小

所以可以想到二分

把所有大于mid时间的航线打上标记,显然删边只能在所有这些航线的公共路径上

要如何快速打标记是个问题

二分已经有一个log,所以只能承受O(n)的判断

如果能知道一条边的经过次数,那么就知道这条边是否在公共路径上

容易想到树上差分,预处理一波 lca 后复杂度可行

删边肯定贪心地删能删的最长边

要如何判断删边后是否最长路径小于mid呢

显然可以预处理出不删前的最长路径

如果最长路径减去删的边 ≤ mid 那么其他路径减删去的边肯定不大于mid(注意删去的边在所有原长超过mid的路径上)

至于其他原长小于 mid 的路径根本不用考虑

所以总结一下就是二分+树上差分

luogu第13个点真是用sang心xin良bing苦kuang,把复杂度卡满了

求LCA可能用树剖会快一点,然而懒得写...

#include
#include
#include
#include
#include
using namespace std;inline int read(){ register int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f;}const int N=3e5+7;int fir[N],from[N<<1],to[N<<1],val[N<<1],cntt;inline void add(int &a,int &b,int &c){ from[++cntt]=fir[a]; fir[a]=cntt; to[cntt]=b; val[cntt]=c; }int f[N][21],dep[N],dis[N],frm[N];//f和dep用来求LCA,dis是点到根的距离,用来求最长路径,frm是连接父节点的边的编号void dfs1(int &x,int &fa)//第一遍dfs处理f,dep,dis,frm{ f[x][0]=fa; dep[x]=dep[fa]+1; for(int i=1;i<=19;i++) f[x][i]=f[f[x][i-1]][i-1]; for(int i=fir[x];i;i=from[i]) { int &v=to[i]; if(v==fa) continue; dis[v]=dis[x]+val[i]; frm[v]=i; dfs1(v,x); }}inline int LCA(int x,int y)//求LCA{ if(dep[x]
=0;i--) if(dep[f[x][i]]>=dep[y]) x=f[x][i]; if(x==y) return x; for(int i=19;i>=0;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; return f[x][0];}int n,m,cnt[N],lca[N],sum[N],tot,mxlen,rt=1;//cnt是差分数组,lca顾名思义,sum[i]是第i条路径的长度,tot记录有几条边原长大于mid,mxlen是最长路径长度,rt是根节点struct data{ int a,b;}d[N];//存运输计划int pos;//记录最长边的编号void dfs2(int &x)//dfs2处理每条边经过次数{ for(int i=fir[x];i;i=from[i]) { int &v=to[i]; if(v==f[x][0]) continue; dfs2(v); cnt[x]+=cnt[v]; } if(cnt[x]==tot&&val[frm[x]]>val[pos]) pos=frm[x];//如果当前节点被所有大于mid的边经过则考虑更新pos}inline bool pd(int &p)//判断合法性,p就是mid{ tot=pos=0; memset(cnt,0,sizeof(cnt));//初始化 for(register int i=1;i<=m;i++) { if(sum[i]<=p) continue; cnt[d[i].a]++; cnt[d[i].b]++; cnt[lca[i]]-=2; tot++; //记录差分 } dfs2(rt); return mxlen-val[pos]>p ? 0 : 1;//判断}int main(){ int a,b,c; n=read(); m=read(); for(register int i=1;i
>1; pd(mid) ? r=mid-1 : l=mid+1; } printf("%d",l); return 0;}

 

转载于:https://www.cnblogs.com/LLTYYC/p/9828248.html

你可能感兴趣的文章
Linux 终端连接工具 XShell v6.0.01 企业便携版
查看>>
JS写一个简单日历
查看>>
Python 发 邮件
查看>>
mysql忘记密码的解决办法
查看>>
全面分析Java的垃圾回收机制2
查看>>
[Code Festival 2017 qual A] C: Palindromic Matrix
查看>>
修改博客园css样式
查看>>
Python3 高阶函数
查看>>
初始面向对象
查看>>
leetcode Letter Combinations of a Phone Number
查看>>
Unity 5.4 测试版本新特性---因吹丝停
查看>>
7.5 文件操作
查看>>
MyEclipse中将普通Java项目convert(转化)为Maven项目
查看>>
node js 安装.node-gyp/8.9.4 权限 无法访问
查看>>
windows基本命令
查看>>
VMware中CentOS设置静态IP
查看>>
[poj1006]Biorhythms
查看>>
Hyper-V虚拟机上安装一个图形界面的Linux系统
查看>>
Hover功能
查看>>
js千分位处理
查看>>