NOIP2015提高组 运输计划 题解
题目链接:点这里
题目描述
公元 2044 年,人类进入了宇宙纪元。
L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所有星球。
小 P 掌管一家物流公司, 该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 u_i 号星球沿最快的宇航路径飞行到 v_i号星球去。显然,飞船驶过一条航道是需要时间的,对于航道 j,任意飞船驶过它所花费的时间为 t_j,并且任意两艘飞船之间不会产生任何干扰。
为了鼓励科技创新, L 国国王同意小 P 的物流公司参与 L 国的航道建设,即允许小 P 把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。
在虫洞的建设完成前小 P 的物流公司就预接了 m 个运输计划。在虫洞建设完成后,这 m 个运输计划会同时开始,所有飞船一起出发。当这 m 个运输计划都完成时,小 P 的物流公司的阶段性工作就完成了。
如果小 P 可以自由选择将哪一条航道改造成虫洞, 试求出小 P 的物流公司完成阶段性工作所需要的最短时间是多少?
输入格式
第一行包括两个正整数 n,m,表示 L 国中星球的数量及小 P 公司预接的运输计划的数量,星球从 1 到 n 编号。
接下来 n−1 行描述航道的建设情况,其中第 i 行包含三个整数 a_i, b_i 和 t_i,表示第 iii 条双向航道修建在 a_i 与 b_i 两个星球之间,任意飞船驶过它所花费的时间为 t_i。
接下来 m 行描述运输计划的情况,其中第 j 行包含两个正整数 u_j 和 v_j,表示第 jjj 个运输计划是从 u_j 号星球飞往 v_j号星球。
输出格式
输出格式
一个整数,表示小 P 的物流公司完成阶段性工作所需要的最短时间。
一句话题意
给出一棵n个节点的有边权树,设dis(i,j)表示i到j的距离,给出m个请求a_i,b_i,问如果将一条边权改为0,使max( dis(a_i,b_i) ) (1 <= i <= m)最小
一句话思路 二分答案+LCA倍增+树上差分
思路
首先看到使max最小第一个想到二分答案
设mid为所用的最短时间,如果ans为最小时间,那么ans+t时间之内也一定能完成,但ans-t却不能,因此满足单调性
接下来思考对于每个点对(a_i,b_i) (1 <= i <= m),如果要求他们的距离,O(n)的暴力肯定是不能接受的,所以考虑用LCA倍增优化
然后考虑怎么写check:对于dis大于mid的点对x,y,标记他们互相到达经过的边(设共计cnt个点对满足条件),最后找到标记次数为cnt次,长度最大的边,并用最大的dis 减去这条边长(一定要为cnt次是因为如果不是cnt次,那么一定会有一对点对之间距离不能减去这条边长,导致这个距离大于mid;而找长度最大的边自然是贪心思想:减去更大的长度更容易使最长的边长<=mid)
但是如果一个一个的标记的话时间复杂度就又变成O(n^2)的了,所以考虑树上差分:对于点对(u,v),分别将book[u],book[v] 分别加上 1,并将book[LCA(u,v)]减去2(这里和有些其他题解不同(TA们会把LCA(u,v) 和 fa[LCA(u,v)] 分别减去1),但是这里我标记的方法是对于一条边u -> fa[u] 标记u点,所以是将LCA(u,v) 减去2,而不是分别减1),然后重新跑一遍dfs作前缀和,复原每条边的真实标记,这样的话只需要O(n)就能跑完
最终时间复杂度
O(n * log(n * maxt) + n * log(n) )
(二分答案和树上差分) (预处理点对的LCA和距离)
上代码
#include<bits/stdc++.h> using namespace std; inline int read(){ 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 << 3) + (x << 1) + ch - '0';ch = getchar();} return x * f; } int n, m; const int maxn = 3e5 + 10,maxt = 1000; int head[maxn], tot; struct questions{ int u, v, LCA, dist; }ask[maxn]; struct edge{ int topoint, nextedge, weight; }e[maxn * 2]; void add(int u,int v,int w){ e[++tot].nextedge = head[u]; e[tot].topoint = v; e[tot].weight = w; head[u] = tot; } const int max2 = 20; int dep[maxn], fa[maxn][max2 + 1], dis[maxn][max2 + 1]; void dfs(int u,int father,int depth,int dist){ fa[u][0] = father; dep[u] = depth; dis[u][0] = dist; for(int i = head[u];i;i = e[i].nextedge){ int v = e[i].topoint, w = e[i].weight; if(v == father)continue; dfs(v,u,depth + 1,w); } } void init(){ for(int j = 1;j <= max2;j++){ for(int i = 1;i <= n;i++){ fa[i][j] = fa[fa[i][j - 1]][j - 1]; dis[i][j] = dis[i][j - 1] + dis[fa[i][j - 1]][j - 1]; } } } questions getLCA(int u,int v){ questions tmp; tmp.u = u; tmp.v = v; if(dep[u] < dep[v])swap(u,v); int dist = 0, father = 0; if(dep[u] != dep[v]) for(int i = max2;i >= 0;i--){ if(dep[fa[u][i]] >= dep[v]){ dist += dis[u][i]; u = fa[u][i]; } } if(u == v){ tmp.dist = dist; tmp.LCA = u; return tmp; } for(int i = max2;i >= 0;i--){ if(fa[u][i] != fa[v][i]){ dist += (dis[u][i] + dis[v][i]); u = fa[u][i]; v = fa[v][i]; } } tmp.dist = dist + dis[u][0] + dis[v][0];tmp.LCA = fa[u][0]; return tmp; } struct cmp{ bool operator()(questions a,questions b){ return a.dist > b.dist; } }; int val[maxn]; void dfs1(int u,int father){ for(int i = head[u];i;i = e[i].nextedge){ int v = e[i].topoint; if(v == father)continue; dfs1(v,u); val[u] += val[v]; } } bool check(int mid){ int nn = 0; memset(val,0,sizeof(val)); for(int i = 1;i <= m;i++){ if(ask[i].dist <= mid)break; val[ask[i].u]++; val[ask[i].v]++; val[ask[i].LCA] -= 2; nn++; } if(!nn)return true; dfs1(1,0); int maxn = 0; for(int i = 1;i <= n;i++){ if(val[i] == nn){ maxn = max(maxn,dis[i][0]); } } return ask[1].dist - maxn <= mid; } signed main(){ n = read(); m = read(); int u, v, w; for(int i = 1;i < n;i++){ u =read(); v = read(); w = read(); add(u,v,w); add(v,u,w); } dfs(1,0,0,0); init(); for(int i = 1;i <= m;i++){ u = read(); v = read(); ask[i] = getLCA(u,v); } sort(ask + 1,ask + 1 + m,cmp()); int l = 0, r = n * maxt, mid = 0; while(l < r){ mid = (l + r) >> 1; if(!check(mid))l = mid + 1; else r = mid; } printf("%d\n",l); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】