题解 [NOIP2015 提高组] 运输计划
闲话:虽说是紫题,但慢慢想还是完全没有问题的。
由于 个运输计划同时开始,所以耗费时间就是最慢的飞船耗费的时间(即最长时间)。考虑到题目让求最短时间,也就是最长的最短,可以二分。
考虑二分最长时间(记作 ),那么将所有路径分成两类,一类是原来耗费的时间就小于等于 的,这部分路径不用处理;另一类则相反,需要将某一条边的权值变成 ,判断是否合法,计算耗费的时间可以用边前缀和。那么肯定要找出不合法路径的公共边,由于只能修改一条边权,所以如果不合法边没有 条公共边,是不可能符合要求的。对于查找公共边,我的做法是:先将不合法边进行边差分,跑一遍自底向上的 求每条边的经过次数,若经过次数等于不合法边的数量,则成立。
找出公共边后,贪心的思考,肯定要将其中最大的边去掉,在找一遍最大的边,与最大的不合法路径相减判断即可。
由于本题卡常,对于 部分需写树剖预处理,本人使用倍增,故只拿 分。
代码:
#include<bits/stdc++.h> using namespace std; typedef long long LL; LL read() { LL sum=0,flag=1; char c=getchar(); while(c<'0'||c>'9') { if(c=='-') flag=-1; c=getchar(); } while(c>='0'&&c<='9') { sum=sum*10+c-'0'; c=getchar(); } return sum*flag; } const int N=3e5+10; int n,m; int u[N],v[N]; int a[N],b[N],c[N],t[N]; int tot,to[N<<1],nxt[N<<1],h[N],w[N<<1],tag[N<<1]; int dep[N],f[N][21]; int diff[N],sdf[N]; int sum[N]; void add(int x,int y,int z,int k) { to[++tot]=y; w[tot]=z; tag[tot]=k; nxt[tot]=h[x]; h[x]=tot; } void dfs1(int nd,int fa) { dep[nd]=dep[fa]+1; for(int i=0;i<=19;i++) f[nd][i+1]=f[f[nd][i]][i]; for(int i=h[nd];i;i=nxt[i]) { int x=to[i]; if(x==fa) continue; f[x][0]=nd; sum[x]=sum[nd]+w[i]; dfs1(x,nd); } } int LCA(int x,int y) { if(dep[x]<dep[y]) { swap(x,y); } for(int i=20;i>=0;i--) { if(dep[f[x][i]]>=dep[y]) x=f[x][i]; if(x==y) return x; } for(int i=20;i>=0;i--) { if(f[x][i]!=f[y][i]) { x=f[x][i]; y=f[y][i]; } } return f[x][0]; } void dfs2(int nd,int fa) { sdf[nd]=diff[nd]; for(int i=h[nd];i;i=nxt[i]) { int x=to[i]; if(x==fa) continue; dfs2(x,nd); sdf[nd]+=sdf[x]; c[tag[i]]=sdf[x]; } } int check(int k) { for(int i=0;i<=n;i++) { diff[i]=0; sdf[i]=0; c[i]=0; } int maxn=0,cnt=0; for(int i=1;i<=n-1;i++) { int x=u[i],y=v[i],lca=LCA(u[i],v[i]); int he=sum[x]+sum[y]-2*sum[lca]; if(he<=k) continue; maxn=max(maxn,he); cnt++; diff[x]++; diff[y]++; diff[lca]-=2; } dfs2(1,0); int max2=0; for(int i=1;i<=n-1;i++) { if(c[i]==cnt) { max2=max(max2,t[i]); } } if(maxn-max2<=k) return 1; return 0; } int main() { //freopen("a.in","r",stdin); //freopen("a.out","w",stdout); cin>>n>>m; for(int i=1;i<=n-1;i++) { a[i]=read(); b[i]=read(); t[i]=read(); add(a[i],b[i],t[i],i); add(b[i],a[i],t[i],i); } dfs1(1,0); for(int i=1;i<=m;i++) { u[i]=read(); v[i]=read(); } int l=0,r=1e9; while(l<r) { int mid=l+r>>1; if(check(mid)) r=mid; else l=mid+1; } cout<<r; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效